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/12rJJ"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/(`GG(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 Хi0ppcontent/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  , original author * */ /* notice that these valuse are octal. */ const PERM_IRWXU = 00700; /* read, write, execute/search by owner */ const PERM_IRUSR = 00400; /* read permission, owner */ const PERM_IWUSR = 00200; /* write permission, owner */ const PERM_IXUSR = 00100; /* execute/search permission, owner */ const PERM_IRWXG = 00070; /* read, write, execute/search by group */ const PERM_IRGRP = 00040; /* read permission, group */ const PERM_IWGRP = 00020; /* write permission, group */ const PERM_IXGRP = 00010; /* execute/search permission, group */ const PERM_IRWXO = 00007; /* read, write, execute/search by others */ const PERM_IROTH = 00004; /* read permission, others */ const PERM_IWOTH = 00002; /* write permission, others */ const PERM_IXOTH = 00001; /* execute/search permission, others */ const MODE_RDONLY = 0x01; const MODE_WRONLY = 0x02; const MODE_RDWR = 0x04; const MODE_CREATE = 0x08; const MODE_APPEND = 0x10; const MODE_TRUNCATE = 0x20; const MODE_SYNC = 0x40; const MODE_EXCL = 0x80; const PICK_OK = Components.interfaces.nsIFilePicker.returnOK; const PICK_CANCEL = Components.interfaces.nsIFilePicker.returnCancel; const PICK_REPLACE = Components.interfaces.nsIFilePicker.returnReplace; const FILTER_ALL = Components.interfaces.nsIFilePicker.filterAll; const FILTER_HTML = Components.interfaces.nsIFilePicker.filterHTML; const FILTER_TEXT = Components.interfaces.nsIFilePicker.filterText; const FILTER_IMAGES = Components.interfaces.nsIFilePicker.filterImages; const FILTER_XML = Components.interfaces.nsIFilePicker.filterXML; const FILTER_XUL = Components.interfaces.nsIFilePicker.filterXUL; const FTYPE_DIR = Components.interfaces.nsIFile.DIRECTORY_TYPE; const FTYPE_FILE = Components.interfaces.nsIFile.NORMAL_FILE_TYPE; // evald f = fopen("/home/rginda/foo.txt", MODE_WRONLY | MODE_CREATE) // evald f = fopen("/home/rginda/vnk.txt", MODE_RDONLY) var futils = new Object(); futils.umask = PERM_IWOTH | PERM_IWGRP; futils.MSG_SAVE_AS = "Save As"; futils.MSG_OPEN = "Open"; futils.getPicker = function futils_nosepicker(initialPath, typeList, attribs) { const classes = Components.classes; const interfaces = Components.interfaces; const PICKER_CTRID = "@mozilla.org/filepicker;1"; const LOCALFILE_CTRID = "@mozilla.org/file/local;1"; const nsIFilePicker = interfaces.nsIFilePicker; const nsILocalFile = interfaces.nsILocalFile; var picker = classes[PICKER_CTRID].createInstance(nsIFilePicker); if (typeof attribs == "object") { for (var a in attribs) picker[a] = attribs[a]; } else throw "bad type for param |attribs|"; if (initialPath) { var localFile; if (typeof initialPath == "string") { localFile = classes[LOCALFILE_CTRID].createInstance(nsILocalFile); localFile.initWithPath(initialPath); } else { if (!(initialPath instanceof nsILocalFile)) throw "bad type for argument |initialPath|"; localFile = initialPath; } picker.displayDirectory = localFile } if (typeof typeList == "string") typeList = typeList.split(" "); if (typeList instanceof Array) { for (var i in typeList) { switch (typeList[i]) { case "$all": picker.appendFilters(FILTER_ALL); break; case "$html": picker.appendFilters(FILTER_HTML); break; case "$text": picker.appendFilters(FILTER_TEXT); break; case "$images": picker.appendFilters(FILTER_IMAGES); break; case "$xml": picker.appendFilters(FILTER_XML); break; case "$xul": picker.appendFilters(FILTER_XUL); break; default: picker.appendFilter(typeList[i], typeList[i]); break; } } } return picker; } function pickSaveAs (title, typeList, defaultFile, defaultDir) { if (!defaultDir && "lastSaveAsDir" in futils) defaultDir = futils.lastSaveAsDir; var picker = futils.getPicker (defaultDir, typeList, {defaultString: defaultFile}); picker.init (window, title ? title : futils.MSG_SAVE_AS, Components.interfaces.nsIFilePicker.modeSave); var reason; try { reason = picker.show(); } catch (ex) { dd ("caught exception from file picker: " + ex); } var obj = new Object(); obj.reason = reason; obj.picker = picker; if (reason != PICK_CANCEL) { obj.file = picker.file; futils.lastSaveAsDir = picker.file.parent; } else { obj.file = null; } return obj; } function pickOpen (title, typeList, defaultFile, defaultDir) { if (!defaultDir && "lastOpenDir" in futils) defaultDir = futils.lastOpenDir; var picker = futils.getPicker (defaultDir, typeList, {defaultString: defaultFile}); picker.init (window, title ? title : futils.MSG_OPEN, Components.interfaces.nsIFilePicker.modeOpen); var rv = picker.show(); if (rv != PICK_CANCEL) futils.lastOpenDir = picker.file.parent; return {reason: rv, file: picker.file, picker: picker}; } function mkdir (localFile, perms) { if (typeof perms == "undefined") perms = 0766 & ~futils.umask; localFile.create(FTYPE_DIR, perms); } function nsLocalFile(path) { const LOCALFILE_CTRID = "@mozilla.org/file/local;1"; const nsILocalFile = Components.interfaces.nsILocalFile; var localFile = Components.classes[LOCALFILE_CTRID].createInstance(nsILocalFile); localFile.initWithPath(path); return localFile; } function fopen (path, mode, perms, tmp) { return new LocalFile(path, mode, perms, tmp); } function LocalFile(file, mode, perms, tmp) { const classes = Components.classes; const interfaces = Components.interfaces; const LOCALFILE_CTRID = "@mozilla.org/file/local;1"; const FILEIN_CTRID = "@mozilla.org/network/file-input-stream;1"; const FILEOUT_CTRID = "@mozilla.org/network/file-output-stream;1"; const SCRIPTSTREAM_CTRID = "@mozilla.org/scriptableinputstream;1"; const nsIFile = interfaces.nsIFile; const nsILocalFile = interfaces.nsILocalFile; const nsIFileOutputStream = interfaces.nsIFileOutputStream; const nsIFileInputStream = interfaces.nsIFileInputStream; const nsIScriptableInputStream = interfaces.nsIScriptableInputStream; if (typeof perms == "undefined") perms = 0666 & ~futils.umask; if (typeof mode == "string") { switch (mode) { case ">": mode = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE; break; case ">>": mode = MODE_WRONLY | MODE_CREATE | MODE_APPEND; break; case "<": mode = MODE_RDONLY; break; default: throw "Invalid mode ``" + mode + "''"; } } if (typeof file == "string") { this.localFile = new nsLocalFile(file); } else if (file instanceof nsILocalFile) { this.localFile = file; } else { throw "bad type for argument |file|."; } this.path = this.localFile.path; if (mode & (MODE_WRONLY | MODE_RDWR)) { this.outputStream = classes[FILEOUT_CTRID].createInstance(nsIFileOutputStream); this.outputStream.init(this.localFile, mode, perms, 0); } if (mode & (MODE_RDONLY | MODE_RDWR)) { var is = classes[FILEIN_CTRID].createInstance(nsIFileInputStream); is.init(this.localFile, mode, perms, tmp); this.inputStream = classes[SCRIPTSTREAM_CTRID].createInstance(nsIScriptableInputStream); this.inputStream.init(is); } } LocalFile.prototype.write = function fo_write(buf) { if (!("outputStream" in this)) throw "file not open for writing."; return this.outputStream.write(buf, buf.length); } LocalFile.prototype.read = function fo_read(max) { if (!("inputStream" in this)) throw "file not open for reading."; var av = this.inputStream.available(); if (typeof max == "undefined") max = av; if (!av) return null; var rv = this.inputStream.read(max); return rv; } LocalFile.prototype.close = function fo_close() { if ("outputStream" in this) this.outputStream.close(); if ("inputStream" in this) this.inputStream.close(); } LocalFile.prototype.flush = function fo_close() { return this.outputStream.flush(); } PK nt/"$"$#content/chatzilla/lib/xul/munger.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 ChatZilla * * 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 * Samuel Sieb, samuel@sieb.net, MIRC color codes */ function initMunger() { client.linkRE = /((\w[\w-]+):[^<>\[\]()\'\"\s\u201d]+|www(\.[^.<>\[\]()\'\"\s\u201d]+){2,})/; var munger = client.munger = new CMunger(); munger.addRule ("quote", /(``|'')/, insertQuote); munger.addRule ("bold", /(?:\s|^)(\*[^*()]*\*)(?:[\s.,]|$)/, "chatzilla-bold"); munger.addRule ("underline", /(?:\s|^)(\_[^_()]*\_)(?:[\s.,]|$)/, "chatzilla-underline"); munger.addRule ("italic", /(?:\s|^)(\/[^\/()]*\/)(?:[\s.,]|$)/, "chatzilla-italic"); /* allow () chars inside |code()| blocks */ munger.addRule ("teletype", /(?:\s|^)(\|[^|]*\|)(?:[\s.,]|$)/, "chatzilla-teletype"); munger.addRule (".mirc-colors", /(\x03((\d{1,2})(,\d{1,2}|)|))/, mircChangeColor); munger.addRule (".mirc-bold", /(\x02)/, mircToggleBold); munger.addRule (".mirc-underline", /(\x1f)/, mircToggleUnder); munger.addRule (".mirc-color-reset", /(\x0f)/, mircResetColor); munger.addRule (".mirc-reverse", /(\x16)/, mircReverseColor); munger.addRule ("ctrl-char", /([\x01-\x1f])/, showCtrlChar); munger.addRule ("link", client.linkRE, insertLink); munger.addRule ("mailto", /(?:\s|\W|^)((mailto:)?[^<>\[\]()\'\"\s\u201d]+@[^.<>\[\]()\'\"\s\u201d]+\.[^<>\[\]()\'\"\s\u201d]+)/i, insertMailToLink); munger.addRule ("bugzilla-link", /(?:\s|\W|^)(bug\s+#?\d{3,6})/i, insertBugzillaLink); munger.addRule ("channel-link", /(?:\s|\W|^)[@+]?(#[^<>\[\](){}\"\s\u201d]*[^:,.<>\[\](){}\'\"\s\u201d])/i, insertChannelLink); munger.addRule ("face", /((^|\s)[\<\>]?[\;\=\:]\~?[\-\^\v]?[\)\|\(pP\<\>oO0\[\]\/\\](\s|$))/, insertSmiley); munger.addRule ("ear", /(?:\s|^)(\(\*)(?:\s|$)/, insertEar, false); munger.addRule ("rheet", /(?:\s|\W|^)(rhee+t\!*)(?:\s|$)/i, insertRheet); munger.addRule ("word-hyphenator", new RegExp ("(\\S{" + client.MAX_WORD_DISPLAY + ",})"), insertHyphenatedWord); client.enableColors = client.prefs["munger.colorCodes"]; for (var entry in client.munger.entries) { var branch = client.prefManager.prefBranch; if (entry[0] != ".") { try { munger.entries[entry].enabled = branch.getBoolPref("munger." + entry); } catch (ex) { // nada } } } } function CMungerEntry (name, regex, className, enable, tagName) { this.name = name; if (name[0] != ".") this.description = getMsg("munger." + name, null, null); this.enabled = (typeof enable == "undefined" ? true : enable); this.enabledDefault = this.enabled; this.tagName = (tagName) ? tagName : "html:span"; if (regex instanceof RegExp) this.regex = regex; else this.lambdaMatch = regex; if (typeof className == "function") this.lambdaReplace = className; else this.className = className; } function CMunger () { this.entries = new Object(); this.tagName = "html:span"; this.enabled = true; } CMunger.prototype.enabled = true; CMunger.prototype.addRule = function mng_addrule (name, regex, className, enable) { this.entries[name] = new CMungerEntry (name, regex, className, enable); } CMunger.prototype.delRule = function mng_delrule (name) { delete this.entries[name]; } CMunger.prototype.munge = function mng_munge (text, containerTag, data) { var entry; var ary; var wbr, newClass; if (!containerTag) { containerTag = document.createElementNS ("http://www.w3.org/1999/xhtml", this.tagName); } if (this.enabled) { for (entry in this.entries) { if (this.entries[entry].enabled) { if (typeof this.entries[entry].lambdaMatch == "function") { var rval; rval = this.entries[entry].lambdaMatch(text, containerTag, data, this.entries[entry]); if (rval) ary = [(void 0), rval]; else ary = null; } else ary = text.match(this.entries[entry].regex); if ((ary != null) && (ary[1])) { var startPos = text.indexOf(ary[1]); if (typeof this.entries[entry].lambdaReplace == "function") { this.munge (text.substr(0,startPos), containerTag, data); this.entries[entry].lambdaReplace (ary[1], containerTag, data, this.entries[entry]); this.munge (text.substr (startPos + ary[1].length, text.length), containerTag, data); return containerTag; } else { this.munge (text.substr(0,startPos), containerTag, data); var subTag = document.createElementNS ("http://www.w3.org/1999/xhtml", this.entries[entry].tagName); newClass = this.entries[entry].className; if ("hasColorInfo" in data) { if ("currFgColor" in data) newClass += " chatzilla-fg" + data.currFgColor; if ("currBgColor" in data) newClass += " chatzilla-bg" + data.currBgColor; if ("isBold" in data) newClass += " chatzilla-bold"; if ("isUnderline" in data) newClass += " chatzilla-underline"; } subTag.setAttribute ("class", newClass); /* don't let this rule match again */ this.entries[entry].enabled = false; this.munge(ary[1], subTag, data); this.entries[entry].enabled = true; containerTag.appendChild (subTag); this.munge (text.substr (startPos + ary[1].length, text.length), containerTag, data); return containerTag; } } } } } var textNode = document.createTextNode (text); if ("hasColorInfo" in data) { newClass = ""; if ("currFgColor" in data) newClass = "chatzilla-fg" + data.currFgColor; if ("currBgColor" in data) newClass += " chatzilla-bg" + data.currBgColor; if ("isBold" in data) newClass += " chatzilla-bold"; if ("isUnderline" in data) newClass += " chatzilla-underline"; if (newClass != "") { var newTag = document.createElementNS ("http://www.w3.org/1999/xhtml", "html:span"); newTag.setAttribute ("class", newClass); newTag.appendChild (textNode); containerTag.appendChild (newTag); } else { delete data.hasColorInfo; containerTag.appendChild (textNode); } wbr = document.createElementNS ("http://www.w3.org/1999/xhtml", "html:wbr"); containerTag.appendChild (wbr); } else containerTag.appendChild (textNode); return containerTag; } PK r#0HFcontent/chatzilla/chatzilla.xulUT l@?PVDDUx PK kt/WG  content/chatzilla/scripts.xulUT FA?PVDDUx PK g6.'\Y 'content/chatzilla/prefpanel/pref-irc.jsUT c/>QVDDUx/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is ChatZilla. * * The Initial Developer of the Original Code is * ____________________________________________. * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * James Ross, , original author * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the LGPL or the GPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ var strBundle; function getMsg (msgName) { var restCount = arguments.length - 1; if (!strBundle) { strBundle = srGetStrBundle("chrome://chatzilla/locale/chatzilla.properties"); } try { if (restCount == 1 && arguments[1] instanceof Array) { return strBundle.formatStringFromName (msgName, arguments[1], arguments[1].length); } else if (restCount > 0) { var subPhrases = new Array(); for (var i = 1; i < arguments.length; ++i) subPhrases.push(arguments[i]); return strBundle.formatStringFromName (msgName, subPhrases, subPhrases.length); } return strBundle.GetStringFromName (msgName); } catch (ex) { dump ("caught exception getting value for ``" + msgName + "''\n" + ex); return msgName; } } PK g6.(C{{)content/chatzilla/prefpanel/appearance.jsUT b/>QVDDUx/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is ChatZilla. * * The Initial Developer of the Original Code is * ____________________________________________. * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * James Ross, , original author * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the LGPL or the GPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ const nsIFilePicker = Components.interfaces.nsIFilePicker; const czStyleDefault = "chrome://chatzilla/skin/output-default.css"; const czStyleLight = "chrome://chatzilla/skin/output-light.css"; const czStyleDark = "chrome://chatzilla/skin/output-dark.css"; const czStyleFacesDefault = "http://www.hacksrus.com/~ginda/chatzilla/motifs/output-default-faces.css"; const czStyleFacesLight = "http://www.hacksrus.com/~ginda/chatzilla/motifs/output-light-faces.css"; const czStyleFacesDark = "http://www.hacksrus.com/~ginda/chatzilla/motifs/output-dark-faces.css"; function Init() { parent.initPanel("chrome://chatzilla/content/prefpanel/appearance.xul"); var edit = document.getElementById("czStyleCSS"); selectStyle(edit.getAttribute("prefvalue")); } function onChooseFile() { try { var edit = document.getElementById("czStyleCSS"); var oldStyle = edit.getAttribute("prefvalue"); var fpClass = Components.classes["@mozilla.org/filepicker;1"]; var fp = fpClass.createInstance(nsIFilePicker); fp.init(window, getMsg("file_browse_CSS"), nsIFilePicker.modeOpen); fp.appendFilter(getMsg("file_browse_CSS_spec"), "*.css"); fp.appendFilters(nsIFilePicker.filterAll); if (fp.show() == nsIFilePicker.returnOK && fp.fileURL.spec && fp.fileURL.spec.length > 0) selectStyle(fp.fileURL.spec); else selectStyle(oldStyle); } catch(ex) { dump ("caught exception in `onChooseFile`\n" + ex); } } function selectStyle(file) { var edit = document.getElementById("czStyleCSS"); var option = document.getElementById("czStyleCustomCSS"); edit.setAttribute("prefvalue", file); var opts = edit.childNodes[0].childNodes; for (var i = 0; i < opts.length; i++) { if (opts[i].getAttribute("url") == file) { edit.selectedIndex = i; return true; } } option.hidden = false; option.label = file; option.setAttribute("url", file); edit.selectedIndex = 7; return true; } function previewStyle() { var edit = document.getElementById("czStyleCSS"); var gData = new Object(); gData.style = edit.getAttribute("prefvalue"); window.openDialog("chrome://chatzilla/content/prefpanel/appearance-previewCSS.xul", "czPreviewCSS", "chrome,modal,resizable=yes", gData); } PK g6.^m*content/chatzilla/prefpanel/appearance.cssUT a/>QVDDUx #czMungerBold { font-weight: bold; } #czMungerItalic { font-style: italic; } /* FIXME: This doesn't work in XUL due to bug 68841. */ #czMungerUnderline { text-decoration: underline; } #czMungerTeletype { font-family: monospace; } PK mt/-m!!*content/chatzilla/prefpanel/appearance.xulUT FA?QVDDUx