home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / mozil06.zip / bin / chrome / chatzilla.jar / content / chatzilla / static.js < prev   
Text File  |  2000-09-14  |  49KB  |  1,599 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  *
  13.  * The Original Code is ChatZilla
  14.  *
  15.  * The Initial Developer of the Original Code is New Dimensions Consulting,
  16.  * Inc. Portions created by New Dimensions Consulting, Inc. are
  17.  * Copyright (C) 1999 New Dimenstions Consulting, Inc. All
  18.  * Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *  Robert Ginda, rginda@ndcico.com, original author
  22.  */
  23.  
  24. if (DEBUG)
  25.     dd = function (m) { dump ("-*- chatzilla: " + m + "\n"); }
  26. else
  27.     dd = function (){};
  28.  
  29. var client = new Object();
  30.  
  31. client.defaultNick = "IRCMonkey";
  32.  
  33. client.IMAGEDIR = "chrome://chatzilla/skin/images/";
  34. client.CSSDIR = "chrome://chatzilla/skin/";
  35.  
  36. client.COMMAND_CHAR = "/";
  37. client.STEP_TIMEOUT = 500;
  38. //client.UPDATE_DELAY = 500;
  39. client.EXPAND_HEIGHT = "200px";
  40. client.COLLAPSE_HEIGHT = "25px";
  41. client.MAX_MESSAGES = 200;
  42. client.MAX_HISTORY = 50;
  43. /* longest nick to show in display before abbreviating */
  44. client.MAX_NICK_DISPLAY = 14;
  45. /* longest word to show in display before abbreviating, currently
  46.  * only for urls and hostnames onJoin */
  47. client.MAX_WORD_DISPLAY = 35;
  48. client.TYPE = "IRCClient";
  49. client.PRINT_DIRECTION = 1; /*1 => new messages at bottom, -1 => at top */
  50. client.ADDRESSED_NICK_SEP = ", ";
  51.  
  52. client.name = "*client*";
  53. client.viewsArray = new Array();
  54. client.activityList = new Object();
  55. client.uiState = new Object(); /* state of ui elements (visible/collapsed) */
  56. client.inputHistory = new Array();
  57. client.lastHistoryReferenced = -1;
  58. client.incompleteLine = "";
  59. client.isPermanent = true;
  60.  
  61. client.lastTabUp = new Date();
  62. client.DOUBLETAB_TIME = 500;
  63.  
  64. client.stalkingVictims = new Array();
  65.  
  66. CIRCNetwork.prototype.INITIAL_NICK = client.defaultNick;
  67. CIRCNetwork.prototype.INITIAL_NAME = "chatzilla";
  68. CIRCNetwork.prototype.INITIAL_DESC = "New Now Know How";
  69. CIRCNetwork.prototype.INITIAL_CHANNEL = "";
  70. CIRCNetwork.prototype.MAX_MESSAGES = 100;
  71. CIRCNetwork.prototype.IGNORE_MOTD = true;
  72.  
  73. CIRCServer.prototype.READ_TIMEOUT = 0;
  74. CIRCServer.prototype.VERSION_RPLY = "ChatZilla, running under " + 
  75.     navigator.userAgent;
  76.  
  77. CIRCUser.prototype.MAX_MESSAGES = 100;
  78.  
  79. CIRCChannel.prototype.MAX_MESSAGES = 200;
  80.  
  81. CIRCChanUser.prototype.MAX_MESSAGES = 100;
  82.  
  83.  
  84. function initStatic()
  85. {
  86.     var obj;
  87.     
  88.     obj = document.getElementById("input");
  89.     obj.addEventListener("keyup", onInputKeyUp, false);
  90.  
  91.         //obj = document.getElementById("tb[*client*]");
  92.     /*
  93.     client.quickList = new CListBox(document.getElementById("quickList"));
  94.     client.quickList.selectedItemCallback = quicklistCallback;
  95.     */
  96.  
  97.     var saveDir = client.PRINT_DIRECTION;
  98.     client.PRINT_DIRECTION = 1;
  99.     client.display ("Welcome to ChatZilla...\n" +
  100.                     "Use /attach <network-name> connect to a network.\n" +
  101.                     "Where <network-name> is one of [" +
  102.                     keys (client.networks) + "]\n" +
  103.                     "More help is available with /help [<command-name>]",
  104.                     "HELLO");
  105.  
  106.     setCurrentObject (client);
  107.  
  108.     client.onInputCommands();
  109.     
  110.     client.PRINT_DIRECTION = saveDir;
  111.  
  112.     if (!jsenv.HAS_XPCOM)
  113.         client.display ("ChatZilla was not given access to the XPConnect " +
  114.                         "service.  You will not be able to connect to an " +
  115.                         "irc server.  A workaround may be to set the " +
  116.                         "'security.checkxpconnect' pref to false in " +
  117.                         "all.js, or your user prefs.",
  118.                         "ERROR");
  119.     window.onkeypress = onWindowKeyPress;
  120.  
  121.     setMenuCheck ("menu-dmessages", 
  122.                   client.eventPump.getHook ("event-tracer").enabled);
  123.     setMenuCheck ("menu-munger", client.munger.enabled);
  124.     setMenuCheck ("menu-viewicons", client.ICONS_IN_TOOLBAR);
  125.     client.uiState["toolbar"] =
  126.         setMenuCheck ("menu-view-toolbar", isVisible("views-tbox"));
  127.     client.uiState["info"] =
  128.         setMenuCheck ("menu-view-info", isVisible("user-list"));
  129.     client.uiState["status"] =
  130.         setMenuCheck ("menu-view-status", isVisible("status-bar-tbox"));
  131.  
  132.     onSortCol ("usercol-nick");
  133.  
  134.     if (document.location.search)
  135.         gotoIRCURL (document.location.search.substr(1));
  136.     
  137. }
  138.  
  139. function setMenuCheck (id, state)
  140. {
  141.     var m = document.getElementById(id);
  142.     m.setAttribute ("checked", String(Boolean(state)));
  143.     return state;
  144. }
  145.  
  146. function isVisible (id)
  147. {
  148.     var e = document.getElementById(id);
  149.  
  150.     if (!e)
  151.     {
  152.         dd ("** Bogus id '" + id + "' passed to isVisible() **");
  153.         return false;
  154.     }
  155.     
  156.     return (e.getAttribute ("collapsed") != "true");
  157. }
  158.  
  159. function initHost(obj)
  160. {
  161.  
  162.     client.commands = new CCommandManager();
  163.     addCommands (obj.commands);
  164.     
  165.     obj.networks = new Object();
  166.     obj.eventPump = new CEventPump (200);
  167.     
  168.     obj.networks["efnet"] =
  169.         new CIRCNetwork ("efnet", [{name: "irc.mcs.net", port: 6667},
  170.                                    {name: "irc.magic.ca", port: 6667},
  171.                                    {name: "irc.freei.net", port: 6667},
  172.                                    {name: "irc.cs.cmu.edu",   port: 6667}],
  173.                          obj.eventPump);
  174.     obj.networks["moznet"] =
  175.         new CIRCNetwork ("moznet", [{name: "irc.mozilla.org", port: 6667}],
  176.                          obj.eventPump);
  177.     obj.networks["hybridnet"] =
  178.         new CIRCNetwork ("hybridnet", [{name: "irc.ssc.net", port: 6667}],
  179.                          obj.eventPump);
  180.     obj.networks["slashnet"] =
  181.         new CIRCNetwork ("slashnet", [{name: "irc.slashnet.org", port:6667}],
  182.                          obj.eventPump);
  183.     obj.networks["dalnet"] =
  184.         new CIRCNetwork ("dalnet", [{name: "irc.dal.net", port:6667}],
  185.                          obj.eventPump);
  186.     obj.networks["undernet"] =
  187.         new CIRCNetwork ("undernet", [{name: "irc.undernet.org", port:6667}],
  188.                          obj.eventPump);
  189.     
  190.     obj.primNet = obj.networks["efnet"];
  191.  
  192.     if (DEBUG)
  193.         /* hook all events EXCEPT server.poll and *.event-end types
  194.          * (the 4th param inverts the match) */
  195.         obj.eventPump.addHook ([{type: "poll", set: /^(server|dcc-chat)$/},
  196.                                {type: "event-end"}], event_tracer,
  197.                                "event-tracer", true /* negate */,
  198.                                false /* disable */);
  199.  
  200.     obj.munger = new CMunger();
  201.     obj.munger.enabled = true;
  202.     obj.munger.addRule ("you-talking-to-me?", matchMyNick, "");
  203.     //    obj.munger.addRule ("im-stalking-you", matchMyNick, "" );
  204.     obj.munger.addRule
  205.         ("link", /((\w+)\:\/\/[^\<\>\(\)\'\"\s]*|www\.[^\<\>\(\)\'\"\s]+\.[^\<\>\(\)\'\"\s]*)/,
  206.          insertLink);
  207.     obj.munger.addRule
  208.         ("face",
  209.          /((^|\s)[\<\>]?[\;\=\:\8]\~?[\-\^\v]?[\)\|\(pP\<\>oO0\[\]\/\\](\s|$))/,
  210.          insertSmiley);
  211.     obj.munger.addRule ("rheet", /(rhee+t\!*)/i, "rheet");
  212.     obj.munger.addRule ("bold", /(\*[^\*]*\*)/, "bold");
  213.     obj.munger.addRule ("italic", /[^sS](\/[^\/]*\/)/, "italic");
  214.     obj.munger.addRule ("teletype", /(\|[^|]*\|)/, "teletype");
  215.     obj.munger.addRule ("underline1", /^(\_[^\_]*\_)/, "underline");
  216.     obj.munger.addRule ("underline2", /\W(\_[^\_]*\_)/, "underline");
  217.          //obj.munger.addRule ("strikethrough", /(\-.*\-)/, "strikethrough");
  218.     obj.munger.addRule ("smallcap", /(\#[^\#]*\#)/, "smallcap");
  219.     obj.munger.addRule ("word-hyphenator",
  220.                         new RegExp ("(\\S{" + client.MAX_WORD_DISPLAY + ",})"),
  221.                         insertHyphenatedWord);
  222.  
  223.     obj.rdf = new RDFHelper();
  224.     
  225.     obj.rdf.initTree("user-list");
  226.     obj.rdf.setTreeRoot("user-list", obj.rdf.resNullChan);
  227.     
  228. }
  229.  
  230. function matchMyNick (text, containerTag, eventDetails)
  231. {
  232.     if (eventDetails && eventDetails.server)
  233.     {        
  234.         var sv = "(" + eventDetails.server.me.nick + ")";
  235.         if ( client.stalkingVictims.length > 0 ) {
  236.             sv += "|(" + client.stalkingVictims.join( ")|(" ) + ")";
  237.         }
  238.  
  239.         var re = new RegExp("(^|[\\W\\s])" + sv + 
  240.                             "([\\W\\s]|$)", "i");
  241.         if (text.search(re) != -1 || 
  242.             eventDetails.orig.lastNickDisplayed.search(re) != -1)
  243.         {
  244.             containerTag.setAttribute ("directedToMe", "true");
  245.             notifyAttention(eventDetails.orig);
  246.         }
  247.     }
  248.  
  249.     return false;
  250.     
  251. }                                                    
  252.  
  253. function insertLink (matchText, containerTag)
  254. {
  255.  
  256.     var href;
  257.     
  258.     if (matchText.indexOf ("://") == -1)
  259.         href = "http://" + matchText;
  260.     else
  261.         href = matchText;
  262.     
  263.     var anchor = document.createElementNS ("http://www.w3.org/1999/xhtml",
  264.                                            "html:a");
  265.     anchor.setAttribute ("href", href);
  266.     anchor.setAttribute ("target", "_content");
  267.     if (matchText.length >= client.MAX_WORD_DISPLAY)
  268.         matchText = hyphenateWord (matchText, client.MAX_WORD_DISPLAY);
  269.     anchor.appendChild (document.createTextNode (matchText));
  270.     containerTag.appendChild (anchor);
  271.     
  272. }
  273.  
  274. function insertSmiley (emoticon, containerTag)
  275. {
  276.     var src = "";
  277.  
  278.     if (emoticon.search (/\;[\-\^\v]?[\)\>\]]/) != -1)
  279.         src = "face-wink.gif";
  280.     else if (emoticon.search (/[\=\:\8][\-\^\v]?[\)\>\]]/) != -1)
  281.         src = "face-smile.gif";
  282.     else if (emoticon.search (/[\=\:\8][\-\^\v]?[\/\\]/) != -1)
  283.         src = "face-screw.gif";
  284.     else if (emoticon.search (/[\=\:\8]\~[\-\^\v]?\(/) != -1)
  285.         src = "face-cry.gif";
  286.     else if (emoticon.search (/[\=\:\8][\-\^\v]?[\(\<\[]/) != -1)
  287.         src = "face-frown.gif";
  288.     else if (emoticon.search (/\<?[\=\:\8][\-\^\v]?[0oO]/) != -1)
  289.         src = "face-surprise.gif";
  290.     else if (emoticon.search (/[\=\:\8][\-\^\v]?[pP]/) != -1)
  291.         src = "face-tongue.gif";
  292.     else if (emoticon.search (/\>?[\=\:\8][\-\^\v]?[\(\|]/) != -1)
  293.         src = "face-angry.gif";
  294.  
  295.     containerTag.appendChild (document.createTextNode (emoticon));
  296.  
  297.     if (src)
  298.     {
  299.         var img = document.createElementNS ("http://www.w3.org/1999/xhtml",
  300.                                             "html:img");
  301.         img.setAttribute ("src", client.IMAGEDIR + src);
  302.         containerTag.appendChild (img);
  303.     }
  304.     
  305. }
  306.  
  307. function insertHyphenatedWord (longWord, containerTag)
  308. {
  309.     containerTag.appendChild
  310.         (document.createTextNode (hyphenateWord(longWord,
  311.                                                 client.MAX_WORD_DISPLAY)));
  312. }
  313.  
  314. /* timer-based mainloop */
  315. function mainStep()
  316. {
  317.  
  318.     if (!client.output)
  319.         setClientOutput(frames[0].document);
  320.     else
  321.         client.eventPump.stepEvents();
  322.     setTimeout ("mainStep()", client.STEP_TIMEOUT);
  323.     
  324. }
  325.  
  326. function quicklistCallback (element, ndx, ary) 
  327. {   
  328.     /* Check whether the selected attribute == true */
  329.     if (element.getAttribute("selected") == "true")
  330.     {
  331.         /* extract the nick data from the element */
  332.         /* Hmmm, nice walk ... */
  333.         ary.push(element.childNodes[0].childNodes[2].childNodes[0].nodeValue);
  334.     }    
  335. }
  336.  
  337. function getObjectDetails (obj, rv)
  338. {
  339.     if (!rv)
  340.         rv = new Object();
  341.  
  342.     if (!obj || (typeof obj != "object"))
  343.     {
  344.         dd ("** INVALID OBJECT passed to getObjectDetails (" + obj + "). **");
  345.         dd (getStackTrace());
  346.     }
  347.     
  348.     rv.orig = obj;
  349.     
  350.     switch (obj.TYPE)
  351.     {
  352.         case "IRCChannel":
  353.             rv.channel = obj;
  354.             rv.server = rv.channel.parent;
  355.             rv.network = rv.server.parent;
  356.             break;
  357.  
  358.         case "IRCUser":
  359.             rv.user = obj;
  360.             rv.server = rv.user.parent;
  361.             rv.network = rv.server.parent;
  362.             break;
  363.  
  364.         case "IRCChanUser":
  365.             rv.user = obj;
  366.             rv.channel = rv.user.parent;
  367.             rv.server = rv.channel.parent;
  368.             rv.network = rv.server.parent;
  369.             break;
  370.  
  371.         case "IRCNetwork":
  372.             rv.network = obj;
  373.             if (rv.network.isConnected())
  374.                 rv.server = rv.network.primServ;
  375.             break;
  376.  
  377.         case "IRCClient":
  378.             if (obj.lastNetwork)
  379.             {
  380.                 rv.network = obj.lastNetwork;
  381.                 if (rv.network.isConnected())
  382.                     rv.server = rv.network.primServ;
  383.             }
  384.             break;
  385.             
  386.         default:
  387.             /* no setup for unknown object */
  388.             break;
  389.     }
  390.  
  391.     return rv;
  392.     
  393. }
  394.  
  395. function setOutputStyle (styleSheet)
  396. {
  397.     var oc = top.frames[0].document;
  398.  
  399.     oc.close();
  400.     oc.open();
  401.     oc.write ("<html><head>");
  402.     
  403.     if (client.USER_CSS_PRE)
  404.         oc.write("<LINK REL=StyleSheet " +
  405.                  "HREF='" + client.USER_CSS_PRE + "' " +
  406.                  "TYPE='text/css' MEDIA='screen'>");
  407.  
  408.     oc.write("<LINK REL=StyleSheet " +
  409.              "HREF='" + client.CSSDIR + styleSheet + "' " +
  410.              "TYPE='text/css' MEDIA='screen'>");
  411.  
  412.     if (client.USER_CSS_POST)
  413.         oc.write("<LINK REL=StyleSheet " +
  414.                  "HREF='" + client.USER_CSS_POST + "' " +
  415.                  "TYPE='text/css' MEDIA='screen'>");
  416.  
  417.     oc.write ("</head>" +
  418.               "<body><div id='output' class='output-window'></div></body>" +
  419.               "</html>");
  420.  
  421.     oc.close();
  422.  
  423.     client.output = oc.getElementById ("output");
  424.     
  425. }
  426.  
  427. function setClientOutput(doc) 
  428. {
  429.     client.output = doc.getElementById("output");
  430.     if (client.output)
  431.     {
  432.         dd ("Got output element.");
  433.         /* continue processing now: */
  434.         initStatic();
  435.         if (client.STARTUP_NETWORK)
  436.             client.onInputAttach ({inputData: client.STARTUP_NETWORK});
  437.     }
  438.     else
  439.         dd ("ARG!  Couldn't get output element, try again later.");
  440.     
  441. }
  442.  
  443. testURLs =
  444.     ["irc:", "irc://", "irc:///", "irc:///help", "irc:///help,needkey",
  445.     "irc://irc.foo.org", "irc://foo:6666",
  446.     "irc://foo", "irc://irc.foo.org/", "irc://foo:6666/", "irc://foo/",
  447.     "irc://irc.foo.org/,needpass", "irc://foo/,isserver",
  448.     "irc://moznet/,isserver", "irc://moznet/",
  449.     "irc://foo/chatzilla", "irc://irc.foo.org/?msg=hello%20there",
  450.     "irc://irc.foo.org/?msg=hello%20there&ignorethis",
  451.     "irc://irc.foo.org/%23mozilla,needkey?msg=hello%20there&ignorethis",
  452.     "invalids",
  453.     "irc://irc.foo.org/,isnick"];
  454.  
  455. function doURLTest()
  456. {
  457.     for (var u in testURLs)
  458.     {
  459.         dd ("-*- testing url \"" + testURLs[u] + "\"");
  460.         var o = parseIRCURL(testURLs[u]);
  461.         if (!o)
  462.             dd ("-!- PARSE FAILED!");
  463.         else
  464.             dd (dumpObjectTree(o));
  465.         dd ("---");
  466.     }
  467. }
  468.  
  469. function parseIRCURL (url)
  470. {
  471.     var specifiedHost = "";
  472.     
  473.     var rv = new Object();
  474.     rv.spec = url;
  475.     rv.host = client.STARTUP_NETWORK;
  476.     rv.target = "";
  477.     rv.port = 6667;
  478.     rv.msg = "";
  479.     rv.needpass = false;
  480.     rv.needkey = false;
  481.     rv.isnick = false;
  482.     rv.isserver = false;
  483.     
  484.     if (url.search(/^(irc:|irc:\/\/)$/i) != -1)
  485.         return rv;
  486.  
  487.     /* split url into <host>/<everything-else> pieces */
  488.     var ary = url.match (/^irc:\/\/([^\/\s]+)?(\/.*)?\s*$/i);
  489.     if (!ary)
  490.     {
  491.         dd ("chatzilla: parseIRCURL: initial split failed");
  492.         return null;
  493.     }
  494.     var host = ary[1];
  495.     var rest = ary[2];
  496.  
  497.     /* split <host> into server (or network) / port */
  498.     ary = host.match (/^([^\s\:]+)?(\:\d+)?$/);
  499.     if (!ary)
  500.     {
  501.         dd ("chatzilla: parseIRCURL: host/port split failed");
  502.         return null;
  503.     }
  504.     
  505.     if (ary[2])
  506.     {
  507.         if (!ary[1])
  508.         {
  509.             dd ("chatzilla: parseIRCURL: port with no host");
  510.             return null;
  511.         }
  512.         specifiedHost = rv.host = ary[1].toLowerCase();
  513.         rv.isserver = true;
  514.         rv.port = parseInt(ary[2].substr(1));
  515.     }
  516.     else if (ary[1])
  517.     {
  518.         if (client.networks[ary[1]])
  519.             specifiedHost = rv.host = ary[1].toLowerCase();
  520.         else
  521.         {
  522.             specifiedHost = rv.host = ary[1].toLowerCase();
  523.             rv.isserver = true;
  524.         }
  525.     }
  526.  
  527.     if (rest)
  528.     {
  529.         ary = rest.match (/^\/([^\,\?\s]*)?(,[^\?]*)?(\?.*)?$/);
  530.         if (!ary)
  531.         {
  532.             dd ("chatzilla: parseIRCURL: rest split failed '" + rest + "'");
  533.             return null;
  534.         }
  535.         
  536.         rv.target = (ary[1]) ? 
  537.             unescape(ary[1]).toLowerCase().replace("\n", "\\n"): "";
  538.         var params = (ary[2]) ? ary[2].toLowerCase() : "";
  539.         var query = (ary[3]) ? ary[3] : "";
  540.  
  541.         if (params)
  542.         {
  543.             rv.isnick =
  544.                 (params.search (/,\s*isnick\s*,|,\s*isnick\s*$/) != -1);
  545.             if (rv.isnick && !rv.target)
  546.             {
  547.                 dd ("chatzilla: parseIRCURL: isnick w/o target");
  548.                     /* isnick w/o a target is bogus */
  549.                 return null;
  550.             }
  551.         
  552.             rv.isserver =
  553.                 (params.search (/,\s*isserver\s*,|,\s*isserver\s*$/) != -1);
  554.             if (rv.isserver && !specifiedHost)
  555.             {
  556.                 dd ("chatzilla: parseIRCURL: isserver w/o host");
  557.                     /* isserver w/o a host is bogus */
  558.                 return null;
  559.             }
  560.                 
  561.             rv.needpass =
  562.                 (params.search (/,\s*needpass\s*,|,\s*needpass\s*$/) != -1);
  563.  
  564.             rv.needkey =
  565.                 (params.search (/,\s*needkey\s*,|,\s*needkey\s*$/) != -1);
  566.  
  567.         }
  568.  
  569.         if (query)
  570.         {
  571.             ary = query.match
  572.                 (/^\?msg=([^\&]*)$|^\?msg=([^\&]*)\&|\&msg=([^\&]*)\&|\&msg=([^\&]*)$/);
  573.             if (ary)
  574.                 for (var i = 1; i < ary.length; i++)
  575.                     if (ary[i])
  576.                     {
  577.                         rv.msg = unescape(ary[i]).replace ("\n", "\\n");
  578.                         break;
  579.                     }
  580.             
  581.         }
  582.     }
  583.  
  584.     return rv;
  585.     
  586. }
  587.  
  588. function gotoIRCURL (url)
  589. {
  590.     if (typeof url == "string")
  591.         url = parseIRCURL(url);
  592.     
  593.     if (!url)
  594.     {
  595.         window.alert ("Invalid IRC URL '" + url + "'");
  596.         return;
  597.     }
  598.  
  599.     var net;
  600.     var pass = "";
  601.     
  602.     if (url.needpass)
  603.         pass = window.prompt ("Enter a password for the url " + url.spec);
  604.     
  605.     if (url.isserver)
  606.     {
  607.         var alreadyThere = false;
  608.         for (var n in client.networks)
  609.         {
  610.             if ((client.networks[n].isConnected()) &&
  611.                 (client.networks[n].primServ.connection.host == url.host) &&
  612.                 (client.networks[n].primServ.connection.port == url.port))
  613.             {
  614.                 /* already connected to this server/port */
  615.                 net = client.networks[n];
  616.                 alreadyThere = true;
  617.                 break;
  618.             }
  619.         }
  620.  
  621.         if (!alreadyThere)
  622.         {
  623.             dd ("-*- chatzilla: gotoIRCURL: not already connected to " +
  624.                 "server " + url.host + " trying to connect...");
  625.             client.onInputServer ({inputData: url.host + " " + url.port +
  626.                                                   " " + pass});
  627.             net = client.networks[url.host];
  628.             if (!net.pendingURLs)
  629.                 net.pendingURLs = new Array();
  630.             net.pendingURLs.push (url);            
  631.             return;
  632.         }
  633.     }
  634.     else
  635.     /* parsed as a network name */
  636.     {
  637.         net = client.networks[url.host];
  638.         if (!net.isConnected())
  639.         {
  640.             dd ("-*- chatzilla: gotoIRCURL: not already connected to " +
  641.                 "network " + url.host + " trying to connect...");
  642.             client.onInputAttach ({inputData: url.host + " " + pass});
  643.             if (!net.pendingURLs)
  644.                 net.pendingURLs = new Array();
  645.             net.pendingURLs.push (url);            
  646.             return;
  647.         }
  648.     }
  649.     
  650.     /* already connected, do whatever comes next in the url */
  651.     dd ("-*- chatzilla: gotoIRCURL: connected, time to finish parsing '" +
  652.         url + "'");
  653.     if (url.target)
  654.     {
  655.         var key = "";
  656.         if (url.needkey)
  657.             key = window.prompt ("Enter key for url " + url.spec);
  658.         if (url.isnick)
  659.         {
  660.                 /* eek, do nick stuff here */
  661.         }
  662.         else
  663.         {
  664.             var ev = {inputData: url.target + " " + key,
  665.                       network: net, server: net.primServ}
  666.             client.onInputJoin (ev);
  667.             if (url.msg)
  668.             {
  669.                 var msg;
  670.                 if (url.msg.indexOf("\01ACTION") == 0)
  671.                     msg = filterOutput (url.msg, "ACTION", "!ME");
  672.                 else
  673.                     msg = filterOutput (url.msg, "PRIVMSG", "!ME");
  674.                 ev.channel.say (msg);
  675.             }
  676.         }
  677.     }
  678.  
  679. }
  680.  
  681. function updateNetwork(obj)
  682. {
  683.     var o = new Object();
  684.     getObjectDetails (client.currentObject, o);
  685.  
  686.     if (obj && obj != o.network)
  687.         return;
  688.     
  689.     var net = o.network ? o.network.name : "(none)";
  690.     var serv = "(none)", nick = "(unknown)", lag = "(unknown)",
  691.         ping = "(never)";
  692.     if (o.server)
  693.     {
  694.         serv  = o.server.connection.host;
  695.         if (o.server.me)
  696.             nick = o.server.me.properNick;
  697.         lag = (o.server.lag != -1) ? o.server.lag : "(unknown)";
  698.         
  699.         if (o.server.lastPing)
  700.         {
  701.             var mins = String(o.server.lastPing.getMinutes());
  702.             if (mins.length == 1)
  703.                 mins = "0" + mins;
  704.             ping = o.server.lastPing.getHours() + ":" + mins;
  705.         }
  706.         else
  707.             ping = "(never)";
  708.     }
  709.  
  710.     document.getElementById ("net-name").firstChild.data = net;
  711.     document.getElementById ("server-name").firstChild.data = serv;
  712.     document.getElementById ("server-nick").firstChild.data = nick;
  713.     document.getElementById ("server-lag").firstChild.data = lag;
  714.     document.getElementById ("last-ping").firstChild.data = ping;
  715.  
  716. }
  717.  
  718. function updateChannel (obj)
  719. {
  720.     if (obj && obj != client.currentObject)
  721.         return;
  722.     
  723.     var o = new Object();
  724.     getObjectDetails (client.currentObject, o);
  725.  
  726.     var chan = "(none)", l = "(none)", k = "(none)", mode = "(none)",
  727.         users = 0, topicBy = "(nobody)", topic = "(unknown)";
  728.  
  729.     if (o.channel)
  730.     {
  731.         chan = o.channel.name;
  732.         l = (o.channel.mode.limit != -1) ? o.channel.mode.limit : "(none)";
  733.         k = o.channel.mode.key ? o.channel.mode.key : "(none)";
  734.         mode = o.channel.mode.getModeStr();
  735.         if (!mode)
  736.             mode = "(none)";
  737.         users = o.channel.getUsersLength();
  738.         topic = o.channel.topic ? o.channel.topic : "(none)";
  739.         topicBy = o.channel.topicBy ? o.channel.topicBy : "(nobody)";
  740.     }
  741.     
  742.     document.getElementById ("channel-name").firstChild.data = chan;
  743.     document.getElementById ("channel-limit").firstChild.data = l;
  744.     document.getElementById ("channel-key").firstChild.data = k;
  745.     document.getElementById ("channel-mode").firstChild.data = mode;
  746.     document.getElementById ("channel-users").firstChild.data = users;
  747.     document.getElementById ("channel-topic").firstChild.data = topic;
  748.     document.getElementById ("channel-topicby").firstChild.data = topicBy;
  749.  
  750. }
  751.  
  752. function updateTitle (obj)
  753. {
  754.     if ((obj && obj != client.currentObject) || !client.currentObject)
  755.         return;
  756.  
  757.     var tstring = "";
  758.     var o = new Object();
  759.     
  760.     getObjectDetails (client.currentObject, o);
  761.  
  762.     var net = o.network ? o.network.name : "";
  763.  
  764.     switch (client.currentObject.TYPE)
  765.     {
  766.         case "IRCServer":
  767.         case "IRCNetwork":
  768.             var serv = "", nick = "";
  769.             if (o.server)
  770.             {
  771.                 serv  = o.server.connection.host;
  772.                 if (o.server.me)
  773.                     nick = o.server.me.properNick;
  774.             }
  775.             
  776.             if (nick) /* user might be disconnected, nick would be undefined */
  777.                 tstring += "user '" + nick + "' ";
  778.             
  779.             if (net)
  780.                 if (serv)
  781.                     tstring += "attached to '" + net + "' via " + serv;
  782.                 else
  783.                     tstring += "attaching to '" + net + "'";
  784.             
  785.             if (tstring)
  786.                 tstring = "ChatZilla: " + tstring;
  787.             else
  788.                 tstring = "ChatZilla!!";
  789.             break;
  790.             
  791.         case "IRCChannel":
  792.             var chan = "(none)", mode = "", topic = "";
  793.  
  794.             chan = o.channel.name;
  795.             mode = o.channel.mode.getModeStr();
  796.             if (client.uiState["toolbar"])
  797.                 topic = o.channel.topic ? " " + o.channel.topic :
  798.                     " --no topic--";
  799.  
  800.             if (!mode)
  801.                 mode = "no mode";
  802.             tstring = "ChatZilla: " + chan + " (" + mode + ") " + topic;
  803.             break;
  804.  
  805.         case "IRCUser":
  806.             tstring = "ChatZilla: Conversation with " +
  807.                 client.currentObject.properNick;
  808.             break;
  809.  
  810.         default:
  811.             tstring = "ChatZilla!";
  812.             break;
  813.     }
  814.  
  815.     if (!client.uiState["toolbar"])
  816.     {
  817.         var actl = new Array();
  818.         for (var i in client.activityList)
  819.             actl.push ((client.activityList[i] == "!") ? (Number(i) + 1) + "!" : 
  820.                        (Number(i) + 1));
  821.         if (actl.length > 0)
  822.             tstring += " --  Activity [" + actl.join (", ") + "]";
  823.     }
  824.  
  825.     document.title = tstring;
  826.  
  827. }
  828.  
  829. function newInlineText (data, className, tagName)
  830. {
  831.     if (typeof tagName == "undefined")
  832.         tagName = "html:span";
  833.     
  834.     var a = document.createElementNS ("http://www.w3.org/1999/xhtml",
  835.                                       tagName);
  836.     a.setAttribute ("class", className);
  837.  
  838.     switch (typeof data)
  839.     {
  840.         case "string":
  841.             a.appendChild (document.createTextNode (data));
  842.             break;
  843.             
  844.         case "object":
  845.             for (var p in data)
  846.                 if (p != "data")
  847.                     a.setAttribute (p, data[p]);
  848.                 else
  849.                     a.appendChild (document.createTextNode (data[p]));
  850.             break;
  851.  
  852.         case "undefined":
  853.             break;
  854.  
  855.         default:
  856.             dd ("** INVALID TYPE ('" + typeof data + "') passed to " +
  857.                 "newInlineText.");
  858.             break;
  859.             
  860.     }
  861.  
  862.     return a;
  863.     
  864. }
  865.  
  866. function setCurrentObject (obj)
  867. {
  868.     if (!obj.messages)
  869.     {
  870.         dd ("** INVALID OBJECT passed to setCurrentObject **");
  871.         return false;
  872.     }
  873.  
  874.     if (client.currentObject == obj)
  875.         return true;
  876.         
  877.     var tb, userList;
  878.  
  879.     if (client.currentObject)
  880.         tb = getTBForObject(client.currentObject);
  881.     
  882.     if (tb)
  883.         tb.setAttribute ("state", "normal");
  884.  
  885.     if (client.output.firstChild)
  886.         client.output.removeChild (client.output.firstChild);
  887.     client.output.appendChild (obj.messages);
  888.  
  889.     /* Unselect currenrly selected users. */
  890.     userList = document.getElementById("user-list");
  891.     if (userList) 
  892.         /* Remove curently selection items before this tree gets rerooted, because it seems to 
  893.         remember the selections for eternity if not. */
  894.         userList.clearItemSelection ();    
  895.     else
  896.         dd ("setCurrentObject: could not find element with ID='user-list'");        
  897.  
  898.     if (obj.TYPE == "IRCChannel")
  899.         client.rdf.setTreeRoot ("user-list", obj.getGraphResource());
  900.     else
  901.         client.rdf.setTreeRoot ("user-list", client.rdf.resNullChan);
  902.  
  903.     client.currentObject = obj;
  904.     tb = getTBForObject(obj);
  905.     if (tb)
  906.         tb.setAttribute ("state", "current");
  907.  
  908.     var vk = Number(tb.getAttribute("viewKey"));
  909.     delete client.activityList[vk];
  910.  
  911.     updateNetwork();
  912.     updateChannel();
  913.     updateTitle ();
  914.  
  915.     if (client.PRINT_DIRECTION == 1)
  916.         window.frames[0].scrollTo(0, window.frames[0].document.height);
  917.     
  918. }
  919.  
  920. function addHistory (source, obj)
  921. {
  922.     if (!source.messages)
  923.     {
  924.         source.messages =
  925.             document.createElementNS ("http://www.w3.org/1999/xhtml",
  926.                                       "html:table");
  927.         source.messages.setAttribute ("class", "chat-view");
  928.         source.messages.setAttribute ("cellpadding", "0");
  929.         source.messages.setAttribute ("cellspacing", "0");
  930.         source.messages.setAttribute ("type", source.TYPE);
  931.         source.messages.setAttribute ("width", "100%");
  932.         
  933.         switch (source.TYPE)
  934.         {
  935.             case "IRCChanUser":
  936.             case "IRCUser":
  937.                 source.messages.setAttribute ("nick", source.nick);
  938.                 break;
  939.  
  940.             case "IRCNetwork":
  941.             case "IRCChannel":
  942.             case "IRCClient":
  943.                 source.messages.setAttribute ("name", source.name);
  944.                 break;
  945.  
  946.             default:
  947.                 dd ("** 'source' has INVALID TYPE in addHistory **");
  948.                 break;
  949.         }       
  950.     }
  951.  
  952.     var needScroll = false;
  953.     var w = window.frames[0];
  954.     
  955.     if (client.PRINT_DIRECTION == 1)
  956.     {
  957.         if ((w.document.height - (w.innerHeight + w.pageYOffset)) <
  958.             (w.innerHeight / 3))
  959.             needScroll = true;
  960.         source.messages.appendChild (obj);
  961.     }
  962.     else
  963.         source.messages.insertBefore (obj, source.messages.firstChild);
  964.     
  965.     if (source.MAX_MESSAGES)
  966.     {
  967.         if (typeof source.messageCount != "number")
  968.             source.messageCount = 1;
  969.         else
  970.             source.messageCount++;
  971.  
  972.         if (source.messageCount > source.MAX_MESSAGES)
  973.             if (client.PRINT_DIRECTION == 1)
  974.                 source.messages.removeChild (source.messages.firstChild);
  975.             else
  976.                 source.messages.removeChild (source.messages.lastChild);
  977.     }
  978.  
  979.     if (needScroll && client.currentObject == source)
  980.         w.scrollTo (w.pageXOffset, w.document.height);
  981.     
  982. }
  983.  
  984. function notifyActivity (source)
  985. {
  986.     if (typeof source != "object")
  987.         source = client.viewsArray[source].source;
  988.     
  989.     var tb = getTBForObject (source, true);
  990.     var vk = Number(tb.getAttribute("viewKey"));
  991.     
  992.     if (client.currentObject != source)
  993.     {
  994.         if (tb.getAttribute ("state") == "normal")
  995.         {       
  996.             tb.setAttribute ("state", "activity");
  997.             if (!client.activityList[vk])
  998.             {
  999.                 client.activityList[vk] = "+";
  1000.                 updateTitle();
  1001.             }
  1002.         }
  1003.         else if (tb.getAttribute("state") == "activity")
  1004.             /* if act light is already lit, blink it real quick */
  1005.         {
  1006.             tb.setAttribute ("state", "normal");
  1007.             setTimeout ("notifyActivity(" + vk + ");", 200);
  1008.         }
  1009.         
  1010.     }
  1011.     
  1012. }
  1013.  
  1014. function notifyAttention (source)
  1015. {
  1016.     if (typeof source != "object")
  1017.         source = client.viewsArray[source].source;
  1018.     
  1019.     var tb = getTBForObject (source, true);
  1020.     var vk = Number(tb.getAttribute("viewKey"));
  1021.  
  1022.     if (client.currentObject != source)
  1023.     {
  1024.         tb.setAttribute ("state", "attention");
  1025.         client.activityList[vk] = "!";
  1026.         updateTitle();
  1027.     }
  1028.  
  1029.     if (client.FLASH_WINDOW)
  1030.         window.GetAttention();
  1031.     
  1032. }
  1033.  
  1034. /* gets the toolbutton associated with an object
  1035.  * if |create| is present, and true, create if not found */
  1036. function getTBForObject (source, create)
  1037. {
  1038.     var name;
  1039.  
  1040.     if (!source)
  1041.     {
  1042.         dd ("** UNDEFINED  passed to getTBForObject **");
  1043.         dd (getStackTrace());
  1044.         return;
  1045.     }
  1046.     
  1047.     create = (typeof create != "undefined") ? Boolean(create) : false;
  1048.  
  1049.     switch (source.TYPE)
  1050.     {
  1051.         case "IRCChanUser":
  1052.         case "IRCUser":
  1053.             name = source.nick;
  1054.             break;
  1055.             
  1056.         case "IRCNetwork":
  1057.         case "IRCChannel":
  1058.         case "IRCClient":
  1059.             name = source.name;
  1060.             break;
  1061.  
  1062.         default:
  1063.             dd ("** INVALID OBJECT passed to getTBForObject **");
  1064.             return;
  1065.     }
  1066.  
  1067.     var tb, id = "tb[" + name + "]";
  1068.     var matches = 1;
  1069.  
  1070.     for (var i in client.viewsArray)
  1071.     {
  1072.         if (client.viewsArray[i].source == source)
  1073.         {
  1074.             tb = client.viewsArray[i].tb;
  1075.             break;
  1076.         }
  1077.         else
  1078.             if (client.viewsArray[i].tb.getAttribute("id") == id)
  1079.                 id = "tb[" + name + "<" + (++matches) + ">]";
  1080.     }
  1081.  
  1082.     if (!tb && create) /* not found, create one */
  1083.     {
  1084.         var views = document.getElementById ("views-tbar-inner");
  1085.         tb = document.createElement ("menubutton");
  1086.         tb.setAttribute ("onclick", "onTBIClick('" + id + "');");
  1087.         
  1088.         //tb.addEventListener("command", onTBIClickTempHandler, false);
  1089.         
  1090.         var aclass = (client.ICONS_IN_TOOLBAR) ?
  1091.             "activity-button-image" : "activity-button-text";
  1092.         
  1093.         tb.setAttribute ("class", "menubutton " + aclass);
  1094.         tb.setAttribute ("id", id);
  1095.         tb.setAttribute ("state", "normal");
  1096.  
  1097.         client.viewsArray.push ({source: source, tb: tb});
  1098.         tb.setAttribute ("viewKey", client.viewsArray.length - 1);
  1099.         if (matches > 1)
  1100.             tb.setAttribute ("value", name + "<" + matches + ">");
  1101.         else
  1102.             tb.setAttribute ("value", name);
  1103.  
  1104.         views.appendChild (tb);
  1105.     }
  1106.  
  1107.     return tb;
  1108.     
  1109. }
  1110.  
  1111. /*
  1112.  * This is used since setAttribute is funked up right now.
  1113.  */
  1114. function onTBIClickTempHandler (e)
  1115.   
  1116.     dd ("onTBIClickTempHandler called");
  1117.     
  1118.     var id = "tb[" + e.target.getAttribute("value") + "]";
  1119.  
  1120.     var tb = document.getElementById (id);
  1121.     var view = client.viewsArray[tb.getAttribute("viewKey")];
  1122.    
  1123.     setCurrentObject (view.source);
  1124.  
  1125. }
  1126.  
  1127. function deleteToolbutton (tb)
  1128. {
  1129.     var i, key = Number(tb.getAttribute("viewKey"));
  1130.     
  1131.     if (!isNaN(key))
  1132.     {
  1133.         if (!client.viewsArray[key].source.isPermanent)
  1134.         {
  1135.             /* re-index higher toolbuttons */
  1136.             for (i = key + 1; i < client.viewsArray.length; i++)
  1137.             {
  1138.                 client.viewsArray[i].tb.setAttribute ("viewKey", i - 1);
  1139.             }
  1140.             arrayRemoveAt(client.viewsArray, key);
  1141.             var tbinner = document.getElementById("views-tbar-inner");
  1142.             tbinner.removeChild(tb);
  1143.         }
  1144.         else
  1145.         {
  1146.             window.alert ("Current view cannot be deleted.");
  1147.             return -1;
  1148.         }
  1149.             
  1150.     }
  1151.     else
  1152.         dd  ("*** INVALID OBJECT passed to deleteToolButton (" + tb + ") " +
  1153.              "no viewKey attribute. (" + key + ")");
  1154.  
  1155.     return key;
  1156.  
  1157. }
  1158.  
  1159. function filterOutput (msg, msgtype)
  1160. {
  1161.  
  1162.     for (var f in client.outputFilters)
  1163.         if (client.outputFilters[f].enabled)
  1164.             msg = client.outputFilters[f].func(msg, msgtype);
  1165.  
  1166.     client.currentObject.display (msg, msgtype, "!ME");
  1167.     
  1168.     return msg;
  1169.     
  1170. }
  1171.     
  1172. client.sayToCurrentTarget =
  1173. function cli_say(msg)
  1174. {
  1175.  
  1176.     switch (client.currentObject.TYPE)
  1177.     {
  1178.         case "IRCChannel":
  1179.         case "IRCUser":
  1180.         case "IRCChanUser":
  1181.             msg = filterOutput (msg, "PRIVMSG");
  1182.             client.currentObject.say (msg);
  1183.             break;
  1184.  
  1185.         case "IRCClient":
  1186.             client.onInputEval ({inputData: msg});
  1187.             break;
  1188.  
  1189.         default:
  1190.             client.display ("No default action for objects of type '" +
  1191.                             client.currentObject.TYPE + "'", "ERROR");
  1192.             break;
  1193.     }
  1194.  
  1195. }
  1196.  
  1197. client.display =
  1198. function cli_display (message, msgtype)
  1199. {
  1200.     var ary = message.split ("\n");
  1201.  
  1202.     var msgRow = newInlineText (
  1203.         {network : "{LOCAL}", msgtype: msgtype}, "msg", "html:tr");
  1204.  
  1205.     var msg = newInlineText (
  1206.         {data: "[" + msgtype + "]", network: "{LOCAL}", msgtype: msgtype},
  1207.         "msg-type", "html:td");
  1208.  
  1209.     msgRow.appendChild(msg);
  1210.  
  1211.     var msgData = newInlineText (
  1212.         {network: "{LOCAL}", msgtype: msgtype},
  1213.         "msg-data", "html:td");
  1214.     
  1215.     for (var l in ary)
  1216.     {
  1217.         msgData.appendChild(newInlineText (ary[l]));
  1218.         msgData.appendChild
  1219.             (document.createElementNS ("http://www.w3.org/1999/xhtml",
  1220.                                        "html:br"));
  1221.     }
  1222.  
  1223.     msgRow.appendChild (msgData);
  1224.  
  1225.     addHistory (this, msgRow);
  1226.     
  1227.     notifyActivity (this);
  1228.  
  1229. }
  1230.  
  1231. client.quit =
  1232. function cli_quit (reason)
  1233. {
  1234.     
  1235.     for (var n in client.networks)
  1236.         if (client.networks[n].primServ)
  1237.             client.networks[n].quit (reason);
  1238.     
  1239. }
  1240.  
  1241. CIRCNetwork.prototype.display =
  1242. function net_display (message, msgtype)
  1243. {
  1244.     var ary = message.split ("\n");
  1245.  
  1246.     var msgRow = newInlineText (
  1247.         {network: this.name, msgtype: msgtype},
  1248.         "msg", "html:tr");
  1249.     
  1250.     var msg = newInlineText (
  1251.         {data: "[" + msgtype + "]", network: this.name, msgtype: msgtype},
  1252.         "msg-type", "html:td");
  1253.  
  1254.     msgRow.appendChild(msg);
  1255.         
  1256.     var msgData = newInlineText (
  1257.         {network: this.name, msgtype: msgtype}, "msg-data", "html:td");
  1258.     
  1259.     for (var l in ary)
  1260.     {
  1261.         msgData.appendChild(newInlineText(ary[l]));
  1262.         msgData.appendChild
  1263.             (document.createElementNS ("http://www.w3.org/1999/xhtml",
  1264.                                        "html:br"));
  1265.     }
  1266.  
  1267.     msgRow.appendChild (msgData);
  1268.     
  1269.     addHistory (this, msgRow);
  1270.     notifyActivity (this);
  1271.  
  1272. }
  1273.  
  1274. CIRCUser.prototype.display =
  1275. function user_display(message, msgtype, sourceNick)
  1276. {
  1277.     var ary = message.split ("\n");
  1278.  
  1279.     if (this.TYPE == "IRCUser")
  1280.     {
  1281.         var msgRow = newInlineText (
  1282.             {network: this.parent.parent.name, user: this.nick,
  1283.              msgtype: msgtype},
  1284.             "msg", "html:tr");
  1285.     
  1286.         var nickText;
  1287.         var realNick = (!sourceNick || sourceNick != "!ME") ? this.properNick :
  1288.             this.parent.me.properNick;
  1289.  
  1290.         var displayNick = hyphenateWord (realNick, client.MAX_NICK_DISPLAY);
  1291.         
  1292.         switch (msgtype)
  1293.         {                
  1294.                 
  1295.             case "ACTION":
  1296.                 nickText = newInlineText ("*" + displayNick + "* ",
  1297.                                           "msg-user", "html:td");
  1298.                 break;
  1299.                 
  1300.             case "NOTICE":
  1301.                 nickText = newInlineText ("[" + displayNick + "] ",
  1302.                                           "msg-user", "html:td");
  1303.                 break;
  1304.  
  1305.             case "PRIVMSG":
  1306.                 nickText = newInlineText (/*"<" +*/ displayNick /*+ ">"*/,
  1307.                                           "msg-user", "html:td");
  1308.                 break;
  1309.                 
  1310.         }
  1311.  
  1312.         if (nickText)
  1313.         {
  1314.             this.mark = (typeof this.mark != "undefined") ? this.mark :
  1315.                 false;
  1316.         
  1317.             if ((this.lastNickDisplayed) &&
  1318.                 (realNick != this.lastNickDisplayed))
  1319.             {
  1320.                 this.mark = !this.mark ;
  1321.                 this.lastNickDisplayed = realNick;
  1322.             }
  1323.             else
  1324.                 this.lastNickDisplayed = realNick;          
  1325.         
  1326.             nickText.setAttribute ("mark", (this.mark) ? "even" : "odd");
  1327.             nickText.setAttribute ("network", this.parent.parent.name);
  1328.             nickText.setAttribute ("user", this.nick);
  1329.             nickText.setAttribute ("msgtype", msgtype);
  1330.             msgRow.appendChild (nickText);   
  1331.         }
  1332.         else
  1333.         {   
  1334.             var msg = newInlineText (
  1335.                 {data: "[" + msgtype + "]", network: this.parent.parent.name,
  1336.                  user: this.nick, msgtype: msgtype},
  1337.                  "msg-type", "html:td");
  1338.             
  1339.             msgRow.appendChild (msg);
  1340.         }
  1341.         
  1342.         var msgData = newInlineText (
  1343.             {network: this.parent.parent.name, msgtype: msgtype},
  1344.              "msg-data", "html:td");
  1345.  
  1346.         msgData.setAttribute ("mark", (this.mark) ? "even" : "odd");
  1347.         msgData.setAttribute ("network", this.parent.parent.name);
  1348.         msgData.setAttribute ("channel", this.name);
  1349.         msgData.setAttribute ("user", nick);
  1350.         msgData.setAttribute ("msgtype", msgtype);
  1351.  
  1352.         for (var l in ary)
  1353.         {
  1354.             if (msgtype.search (/PRIVMSG|ACTION/) != -1)
  1355.                 client.munger.munge(ary[l], msgData, getObjectDetails (this));
  1356.             else
  1357.                 msgData.appendChild(newInlineText (ary[l]));
  1358.             msgData.appendChild
  1359.                 (document.createElementNS ("http://www.w3.org/1999/xhtml",
  1360.                                            "html:br"));
  1361.         }
  1362.  
  1363.         msgRow.appendChild (msgData);
  1364.         
  1365.         addHistory (this, msgRow);
  1366.         notifyActivity (this);
  1367.  
  1368.     }
  1369.     else
  1370.         this.parent.display (message, msgtype, this.nick);
  1371.  
  1372. }
  1373.  
  1374. /**
  1375.  * Retrieves the selected nicks from the user-list
  1376.  * tree object. This grabs the tree element's
  1377.  * selected items, extracts the appropriate text
  1378.  * for the nick, promotes each nick to a CIRCChanUser
  1379.  * instance and returns an array of these objects.
  1380.  */
  1381. CIRCChannel.prototype.getSelectedUsers =
  1382. function my_getselectedusers () 
  1383. {
  1384.  
  1385.     /* Grab a reference to the tree element with ID = user-list . See chatzilla.xul */
  1386.     var tree = document.getElementById("user-list");
  1387.     var cell; /* reference to each selected cell of the tree object */
  1388.     var rv_ary = new Array; /* return value arrray for CIRCChanUser objects */
  1389.  
  1390.     for (var i = 0; i < tree.selectedItems.length; i++)
  1391.     {
  1392.         /* First, set the reference to the XUL element. */
  1393.         cell = tree.selectedItems[i].firstChild.childNodes[2].firstChild;
  1394.  
  1395.         /* Now, create an instance of CIRCChaneUser by passing the text
  1396.        *  of the cell to the getUser function of this CIRCChannel instance.
  1397.        */
  1398.         rv_ary[i] = this.getUser( cell.getAttribute("value") );
  1399.     }
  1400.  
  1401.     /* 
  1402.      *  USAGE NOTE: If the return value is non-null, the caller
  1403.      *  can assume the array is valid, and NOT 
  1404.      *  need to check the length, and vice versa.
  1405.      */
  1406.  
  1407.     return rv_ary.length > 0 ? rv_ary : null;
  1408.  
  1409. }
  1410.  
  1411. CIRCChannel.prototype.getGraphResource =
  1412. function my_graphres ()
  1413. {
  1414.     if (!this.rdfRes)
  1415.     {
  1416.         this.rdfRes = 
  1417.             client.rdf.GetResource(RES_PFX + "CHANNEL:" +
  1418.                                    this.parent.parent.name +
  1419.                                    ":" + this.name);
  1420.             //dd ("created channel resource " + this.rdfRes.Value);
  1421.  
  1422.     }
  1423.     
  1424.     return this.rdfRes;
  1425. }
  1426.  
  1427. CIRCChannel.prototype.display =
  1428. function chan_display (message, msgtype, nick)
  1429. {
  1430.     var ary = message.split ("\n");
  1431.     var nickText;
  1432.  
  1433.     var msgRow = newInlineText (
  1434.         {network: this.parent.parent.name , channel: this.name, user: nick,
  1435.          msgtype: msgtype},
  1436.         "msg", "html:tr");
  1437.     
  1438.     if (nick)
  1439.     {
  1440.         var realNick;
  1441.         
  1442.         if (this.users[nick])
  1443.             realNick = this.users[nick].properNick;
  1444.         else if (nick == "!ME")
  1445.             realNick = this.parent.me.properNick;
  1446.         else    
  1447.             realNick = nick + "?";
  1448.         
  1449.         var displayNick = hyphenateWord (realNick, client.MAX_NICK_DISPLAY);
  1450.  
  1451.         switch (msgtype)
  1452.         {                
  1453.                 
  1454.             case "ACTION":
  1455.                 nickText = newInlineText ("*" + displayNick + "* ",
  1456.                                           "msg-user", "html:td");
  1457.                 break;
  1458.                 
  1459.             case "NOTICE":
  1460.                 nickText = newInlineText ("[" + displayNick + "] ",
  1461.                                           "msg-user", "html:td");
  1462.                 break;
  1463.  
  1464.             case "PRIVMSG":
  1465.                 nickText = newInlineText (/*"<" + */ displayNick /*+ "> "*/,
  1466.                                           "msg-user", "html:td");
  1467.                 break;
  1468.                 
  1469.         }
  1470.     }
  1471.  
  1472.     if (nickText)
  1473.     {
  1474.         if (typeof this.mark == "undefined")
  1475.             this.mark = "even";
  1476.         
  1477.         if ((this.lastNickDisplayed) &&
  1478.             (nick != this.lastNickDisplayed))
  1479.         {
  1480.             this.mark = (this.mark == "odd") ? "even" : "odd";
  1481.             this.lastNickDisplayed = nick;
  1482.         }
  1483.         else
  1484.             this.lastNickDisplayed = nick;                
  1485.  
  1486.         nickText.setAttribute ("mark", this.mark);
  1487.         nickText.setAttribute ("network", this.parent.parent.name);
  1488.         nickText.setAttribute ("channel", this.name);
  1489.         nickText.setAttribute ("user", nick);
  1490.         nickText.setAttribute ("msgtype", msgtype);
  1491.         msgRow.appendChild (nickText);   
  1492.     }
  1493.     else
  1494.     {   
  1495.         var msg = newInlineText (
  1496.             {data: "[" + msgtype + "]", network: this.parent.parent.name,
  1497.                        channel: this.name, user: nick, msgtype: msgtype},
  1498.             "msg-type", "html:td");
  1499.         
  1500.         msgRow.appendChild (msg);
  1501.     }
  1502.  
  1503.     var msgData = newInlineText (
  1504.             {network: this.parent.parent.name, channel: this.name,
  1505.              user: nick, msgtype: msgtype},
  1506.             "msg-data", "html:td");
  1507.     
  1508.     msgData.setAttribute ("mark", this.mark);
  1509.     msgData.setAttribute ("network", this.parent.parent.name);
  1510.     msgData.setAttribute ("channel", this.name);
  1511.     msgData.setAttribute ("user", nick);
  1512.     msgData.setAttribute ("msgtype", msgtype);
  1513.     
  1514.     for (var l in ary)
  1515.     {
  1516.         if (msgtype.search (/PRIVMSG|ACTION|TOPIC/) != -1)
  1517.             client.munger.munge(ary[l], msgData, getObjectDetails (this));
  1518.         else
  1519.             msgData.appendChild(newInlineText (ary[l]));
  1520.         msgData.appendChild
  1521.             (document.createElementNS ("http://www.w3.org/1999/xhtml",
  1522.                                        "html:br"));
  1523.     }
  1524.  
  1525.     msgRow.appendChild (msgData);
  1526.     
  1527.     addHistory (this, msgRow);
  1528.     notifyActivity (this);
  1529.  
  1530. }
  1531.  
  1532. CIRCUser.prototype.getGraphResource =
  1533. function usr_graphres()
  1534. {
  1535.     if (this.TYPE != "IRCChanUser")
  1536.         dd ("** WARNING: cuser.getGraphResource called on wrong object **");
  1537.     
  1538.     var rdf = client.rdf;
  1539.     
  1540.     if (!this.rdfRes)
  1541.     {
  1542.         if (!CIRCUser.nextResID)
  1543.             CIRCUser.nextResID = 0;
  1544.         
  1545.         this.rdfRes = rdf.GetResource (RES_PFX + "CUSER:" + 
  1546.                                        this.parent.parent.parent.name + ":" +
  1547.                                        this.parent.name + ":" +
  1548.                                        CIRCUser.nextResID++);
  1549.         
  1550.             //dd ("created cuser resource " + this.rdfRes.Value);
  1551.         
  1552.         rdf.Assert (this.rdfRes, rdf.resNick, rdf.GetLiteral(this.properNick));
  1553.         if (this.name)
  1554.             rdf.Assert (this.rdfRes, rdf.resUser, rdf.GetLiteral(this.name));
  1555.         else
  1556.             rdf.Assert (this.rdfRes, rdf.resUser, rdf.litUnk);
  1557.         if (this.host)
  1558.             rdf.Assert (this.rdfRes, rdf.resHost, rdf.GetLiteral(this.host));
  1559.         else
  1560.             rdf.Assert (this.rdfRes, rdf.resHost, rdf.litUnk);
  1561.  
  1562.         rdf.Assert (this.rdfRes, rdf.resOp, 
  1563.                     this.isOp ? rdf.litTrue : rdf.litFalse);
  1564.         rdf.Assert (this.rdfRes, rdf.resVoice,
  1565.                     this.isVoice ? rdf.litTrue : rdf.litFalse);
  1566.     }
  1567.  
  1568.     return this.rdfRes;
  1569.  
  1570. }
  1571.  
  1572. CIRCUser.prototype.updateGraphResource =
  1573. function usr_updres()
  1574. {
  1575.     if (this.TYPE != "IRCChanUser")
  1576.         dd ("** WARNING: cuser.updateGraphResource called on wrong object **");
  1577.  
  1578.     if (!this.rdfRes)
  1579.         this.getGraphResource();
  1580.     
  1581.     var rdf = client.rdf;
  1582.     
  1583.     rdf.Change (this.rdfRes, rdf.resNick, rdf.GetLiteral(this.properNick));
  1584.     if (this.name)
  1585.         rdf.Change (this.rdfRes, rdf.resUser, rdf.GetLiteral(this.name));
  1586.     else
  1587.         rdf.Change (this.rdfRes, rdf.resUser, rdf.litUnk);
  1588.     if (this.host)
  1589.         rdf.Change (this.rdfRes, rdf.resHost, rdf.GetLiteral(this.host));
  1590.     else
  1591.         rdf.Change (this.rdfRes, rdf.resHost, rdf.litUnk);
  1592.     
  1593.     rdf.Change (this.rdfRes, rdf.resOp, 
  1594.                 this.isOp ? rdf.litTrue : rdf.litFalse);
  1595.     rdf.Change (this.rdfRes, rdf.resVoice,
  1596.                 this.isVoice ? rdf.litTrue : rdf.litFalse);
  1597. }
  1598.