connection error handling, add build scripts

git-svn-id: https://webim.svn.sourceforge.net/svnroot/webim/trunk@122 c66351dc-e62f-0410-b875-e3a5c0b9693f
This commit is contained in:
Evgeny Gryaznov 2008-09-29 23:24:18 +00:00
parent 99c36bf687
commit 2fcc7ca242
5 changed files with 955 additions and 155 deletions

735
src/messenger/js/JSO.java Normal file
View File

@ -0,0 +1,735 @@
/*
* JavaScript Obfucator is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* JavaScript Obfucator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
import java.util.*;
import java.io.*;
/**
* Obfuscate the JavaScript code.
* updated by Evgeny Gryaznov, March 2006
* @author Shane Ng <gnenahs at poboxes dot com>
*/
public class JSO {
private Random randomizer = new Random(321);
public static final String[] reserved = {
"abstract", "else", "instanceof", "switch", "boolean", "enum", "int",
"synchronized", "break", "export", "interface", "this", "byte", "extends",
"long", "throw", "case", "false", "native", "throws", "catch", "final",
"new", "transient", "char", "finally", "null", "true", "class", "float",
"package", "try", "const", "for", "private", "typeof", "continue", "function",
"protected", "var", "debugger", "goto", "public", "void", "default", "if",
"return", "volatile", "delete", "implements", "short", "while", "do", "import",
"static", "with", "double", "in", "super", "undefined", "arguments"
};
public static final String[] builtIn = {
"history", "packages", "pageXOffset", "pageYOffset", "isNaN", "array", "java",
"plugin", "clientInformation", "prototype", "layer", "layers", "crypto", "date", "secure",
"embed", "navigator", "product", "netscape", "escape", "eval", "sun",
"taint", "fileUpload", "toString", "unescape", "untaint", "frameRate",
"valueOf", "getClass", "encodeURIComponent", "overrideMimeType",
// Types
"Math", "Date", "Array", "RegExp", "Image", "Function", "ActiveXObject",
"Number", "String", "Object", "JavaClass", "JavaObject", "JavaPackage", "JavaArray",
// DOM
"anchor", "image", "area", "checkbox", "password", "radio", "textarea",
"contentDocument", "contentWindow", "document",
"window", "element", "location", "option", "style", "body",
// Properties
"accessKey", "action", "activeElement", "align", "aLink", "aLinkColor", "alt",
"altHTML", "altKey", "appCodeName", "appMinorVersion", "appName", "appVersion",
"autocomplete", "availHeight", "availWidth", "background", "backgroundAttachment",
"backgroundColor", "backgroundImage", "backgroundPosition", "backgroundPositionX",
"backgroundPositionY", "backgroundRepeat", "balance", "behavior", "bgColor",
"bgProperties", "border", "borderBottom", "borderBottomColor", "borderBottomStyle",
"borderBottomWidth", "borderCollapse", "borderColor", "borderColorDark",
"borderColorLight", "borderLeft", "borderLeftColor", "borderLeftStyle",
"borderLeftWidth", "borderRight", "borderRightColor", "borderRightStyle",
"borderRightWidth", "borderStyle", "borderTop", "borderTopColor", "borderTopStyle",
"borderTopWidth", "borderWidth", "bottom", "bottomMargin", "boundingHeight", "boundingLeft",
"boundingTop", "boundingWidth", "browserLanguage", "bufferDepth", "button",
"cancelBubble", "canHaveChildren", "caption", "cellIndex", "cellPadding", "cellSpacing",
"checked", "classid", "className", "clear", "clientHeight", "clientLeft", "clientTop",
"clientWidth", "clientX", "clientY", "clip", "clipBottom", "clipLeft", "clipRight",
"clipTop", "closed", "code", "codeBase", "codeType", "color", "colorDepth", "cols",
"colSpan", "compact", "complete", "content", "cookie", "cookieEnabled", "coords",
"cpuClass", "cssText", "ctrlKey", "cursor", "data", "dataFld", "dataFormatAs",
"dataPageSize", "dataSrc", "defaultCharset", "defaultChecked", "defaultSelected",
"defaultStatus", "defaultValue", "defer", "designMode", "dialogArguments", "dialogHeight",
"dialogLeft", "dialogTop", "dialogWidth", "dir", "direction", "disabled", "display",
"documentElement", "domain", "dropEffect", "dynsrc", "effectAllowed", "encoding", "event",
"expando", "face", "fgColor", "fileCreatedDate", "fileModifiedDate", "fileSize",
"fileUpdatedDate", "filter", "firstChild", "font", "fontFamily", "fontSize",
"fontSmoothingEnabled", "fontStyle", "fontVariant", "fontWeight", "form", "frame",
"frameBorder", "frameSpacing", "fromElement", "hash", "height", "hidden", "host",
"hostname", "href", "hspace", "htmlFor", "htmlText", "httpEquiv", "id", "imeMode",
"indeterminate", "index", "innerHTML", "innerText", "isMap", "isTextEdit", "keyCode",
"lang", "language", "lastChild", "lastModified", "layoutGrid", "layoutGridChar",
"layoutGridCharSpacing", "layoutGridLine", "layoutGridMode", "layoutGridType", "left",
"leftMargin", "length", "letterSpacing", "lineBreak", "lineHeight", "link", "linkColor",
"listStyle", "listStyleImage", "listStylePosition", "listStyleType", "loop", "lowsrc",
"margin", "marginBottom", "marginHeight", "marginLeft", "marginRight", "marginTop",
"marginWidth", "maxLength", "media", "menuArguments", "method", "Methods", "multiple",
"name", "nameProp", "nextSibling", "nodeName", "nodeType", "nodeValue", "noHref",
"noResize", "noShade", "noWrap", "object", "offscreenBuffering", "offsetHeight",
"offsetLeft", "offsetParent", "offsetTop", "offsetWidth", "offsetX", "offsetY",
"onLine", "opener", "outerHTML", "outerText", "overflow", "overflowX", "overflowY",
"owningElement", "padding", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop",
"pageBreakAfter", "pageBreakBefore", "palette", "parent", "parentElement", "parentNode",
"parentStyleSheet", "parentTextEdit", "parentWindow", "pathname", "pixelBottom",
"pixelHeight", "pixelLeft", "pixelRight", "pixelTop", "pixelWidth", "platform",
"pluginspage", "port", "posBottom", "posHeight", "position", "posLeft", "posRight",
"posTop", "posWidth", "previousSibling", "propertyName", "protocol", "qualifier",
"readOnly", "reason", "recordNumber", "recordset", "referrer", "rel",
"repeat", "returnValue", "rev", "right", "rightMargin", "rowIndex", "rowSpan",
"rubyAlign", "rubyOverhang", "rubyPosition", "scopeName", "screenLeft",
"screenTop", "screenX", "screenY", "scrollAmount", "scrollDelay",
"scrollHeight", "scrolling", "scrollLeft", "scrollTop", "scrollWidth", "search",
"sectionRowIndex", "selected", "selectedIndex", "selectorText", "self", "shape",
"shiftKey", "size", "sourceIndex", "span", "specified", "src", "srcElement", "srcFilter",
"srcUrn", "start", "status", "styleFloat", "systemLanguage", "tabIndex", "tableLayout",
"tagName", "tagUrn", "target", "text", "textAlign", "textAutospace", "textDecoration",
"textDecorationLineThrough", "textDecorationNone", "textDecorationOverline",
"textDecorationUnderline", "textIndent", "textJustify", "textTransform", "tFoot", "tHead",
"title", "toElement", "top", "topMargin", "trueSpeed", "type", "unicodeBidi", "uniqueID",
"units", "updateInterval", "URL", "urn", "useMap", "userAgent", "userLanguage", "vAlign",
"value", "vcard_name", "verticalAlign", "visibility", "vLink", "vlinkColor", "volume",
"vspace", "whiteSpace", "width", "wordBreak", "wordSpacing", "wrap", "x",
"XMLDocument", "y", "zIndex",
// non-IE
"outerHeight", "innerHeight", "outerWidth", "innerWidth",
"which",
// collections
"all", "anchors", "applets", "areas", "attributes", "behaviorUrns",
"bookmarks", "boundElements", "cells", "childNodes", "children",
"controlRange", "elements", "embeds", "filters", "forms", "frames",
"images", "imports", "links", "mimeTypes", "options", "plugins", "rows",
"rules", "scripts", "styleSheets", "tBodies", "TextRectangle",
// Methods
"add", "addBehavior", "AddFavorite", "addImport", "addRule", "alert",
"appendChild", "applyElement", "assign", "attachEvent", "back", "blur",
"clearAttributes", "clearData", "clearInterval", "clearRequest",
"clearTimeout", "click", "cloneNode", "close", "collapse", "compareEndPoints",
"componentFromPoint", "confirm", "contains", "createCaption", "createControlRange",
"createElement", "createRange", "createStyleSheet", "createTextNode", "createTextRange",
"createTFoot", "createTHead", "deleteCaption", "deleteCell", "deleteRow", "deleteTFoot",
"deleteTHead", "detachEvent", "doScroll", "duplicate", "elementFromPoint",
"empty", "execCommand", "execScript", "expand", "findText", "firstPage", "focus",
"forward", "getAdjacentText", "getAttribute", "getBookmark", "getBoundingClientRect",
"getClientRects", "getData", "getElementById", "getElementsByName", "getElementsByTagName",
"getExpression", "go", "hasChildNodes", "inRange",
"insertAdjacentElement", "insertAdjacentHTML", "insertAdjacentText", "insertBefore",
"insertCell", "insertRow", "isEqual", "IsSubscribed", "item", "javaEnabled", "lastPage",
"mergeAttributes", "move", "moveBy", "moveEnd", "moveRow", "moveStart", "moveTo",
"moveToBookmark", "moveToElementText", "moveToPoint", "namedRecordset", "navigate",
"NavigateAndFind", "nextPage", "open", "pasteHTML",
"previousPage", "print", "prompt", "queryCommandEnabled", "queryCommandIndeterm",
"queryCommandState", "queryCommandSupported", "queryCommandValue", "recalc", "refresh",
"releaseCapture", "reload", "remove", "removeAttribute", "removeBehavior",
"removeChild", "removeExpression", "removeNode", "removeRule", "replace",
"replaceAdjacentText", "replaceChild", "replaceNode", "reset", "resizeBy",
"resizeTo", "scroll", "scrollBy", "scrollIntoView", "scrollTo", "select",
"setAttribute", "setCapture", "setData", "setEndPoint", "setExpression", "setInterval",
"setTimeout", "ShowBrowserUI", "showHelp", "showModalDialog", "showModelessDialog",
"splitText", "stop", "submit", "swapNode", "tags", "taintEnabled",
"urns", "write", "writeln",
// builtIn
"toUpperCase", "toLowerCase", "match", "substring", "split", "indexOf",
"parseFloat", "parseInt",
"getYear", "getTime", "getMonth", "getFullYear", "getDay", "getDate",
"exec", "join", "call", "floor", "toUTCString",
// events
"onabort", "onafterprint", "onafterupdate", "onbeforecopy", "onbeforecut",
"onbeforeeditfocus", "onbeforepaste", "onbeforeprint", "onbeforeunload",
"onbeforeupdate", "onblur", "onbounce", "oncellchange", "onchange", "onclick",
"oncontextmenu", "oncopy", "oncut", "ondataavailable", "ondatasetchanged", "ondatasetcomplete",
"ondblclick", "ondrag", "ondragend", "ondragenter", "ondragleave", "ondragover",
"ondragstart", "ondrop", "onerror", "onerrorupdate", "onfilterchange", "onfinish",
"onfocus", "onhelp", "onkeydown", "onkeypress", "onkeyup", "onload",
"onlosecapture", "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup",
"onpaste", "onpropertychange", "onreset", "onresize", "onrowenter",
"onrowexit", "onrowsdelete", "onrowsinserted", "onscroll", "onselect", "onselectstart",
"onstart", "onstop", "onsubmit", "onunload",
// Ajax
"XMLHttpRequest", "readyState", "onreadystatechange", "responseXML",
"responseText", "responseBody", "statusText",
"send", "abort", "setRequestHeader", "getResponseHeader", "getAllResponseHeaders",
"timeout"
};
public static final char[] DELIMITER = {'?', ':', '!', '=', '(', ')', '[', ']',
'{', '}', '\r', '\n', '\t', ' ', '\"', '\'', '<', '>', ',', '.', '/',
'\\', '+', '-', '*', '&', '|', '^', '%', ';'
};
public static final String[] alpha = {
"m", "n", "q", "r", "s", "t", "u",
"h", "i", "j", "k", "l", "o", "p",
"d", "e", "f", "g", "a", "b", "c",
"v", "w", "x", "y", "z", "$", "_"
};
public static final HashSet exclusionTokenSet = new HashSet();
public static final HashSet forceReplace = new HashSet();
public static final HashSet forceReplaceInStrings = new HashSet();
public static final HashMap forceTextualReplace = new HashMap();
public static int ref = alpha.length;
public static HashMap map = new HashMap();
public static final String ARG_EXCLUDE_TOKENS = "e=";
public static final String ARG_DESTINATION_DIR = "d=";
public static final String ARG_OBFUSCATE_STRING = "o=";
public static final String ARG_DEBUG = "debug";
public static final String ARG_DEBUGEXCLUDE = "debugnames";
public static final String ARG_REPLACE = "textrepl=";
private double[] stringObfuscationParameter = {0, 0, 0.5};
private String[] file = null;
public static boolean isDebug = false;
public static boolean isExcludeAll = false;
private String destinationDir = null;
private JSOState state = new JSOState();
private String delimiter = new String(DELIMITER);
private HashSet encounteredInStrings = new HashSet();
private HashMap encounteredInStringsFiles = new HashMap();
public static void main(String[] args) throws Exception {
ArrayList fileList = new ArrayList(args.length);
String[] file = null;
String destinationDir = null;
double[] stringObfuscationParameter = {1, .59, 0.5};
if (args.length == 0) {
printUsage();
return;
} else if (args.length > 1) {
for (int i = 0; i < args.length; i++) {
if( args[i].equals(ARG_DEBUG)) {
isDebug = true;
} else if( args[i].equals(ARG_DEBUGEXCLUDE) ) {
isExcludeAll = true;
} else if (args[i].startsWith(ARG_EXCLUDE_TOKENS)) {
readexclusionTokenSet(args[i].substring(ARG_EXCLUDE_TOKENS.length()));
} else if (args[i].startsWith(ARG_DESTINATION_DIR) && destinationDir == null) {
File dir = new File(args[i].substring(ARG_DESTINATION_DIR.length()));
if (!dir.exists() && !dir.mkdirs()) {
System.err.println("Cannot create the output directory \"" + dir.getName() + "\"");
return;
} else if (dir.exists() && dir.isFile()) {
System.err.println("The output parameter \"" + args[i] + "\" is not a directory");
return;
}
destinationDir = dir.getAbsolutePath();
} else if (args[i].startsWith(ARG_OBFUSCATE_STRING)) {
String[] param = args[i].substring(ARG_OBFUSCATE_STRING.length()).split(",", 3);
if (param.length >= 2) {
try {
stringObfuscationParameter[0] = Double.parseDouble(param[0]);
stringObfuscationParameter[1] = Double.parseDouble(param[1]);
if (param.length == 3) {
stringObfuscationParameter[2] = Double.parseDouble(param[2]);
}
} catch (NumberFormatException e) {
System.err.println("The obfuscation parameters are not numbers.");
return;
}
} else {
System.err.println("At least 2 obfuscation parameters are required, e.g. o=0.4,0.7.");
return;
}
} else if( args[i].startsWith(ARG_REPLACE) ) {
String[] param = args[i].substring(ARG_REPLACE.length()).split(",", 3);
if (param.length == 2) {
forceTextualReplace.put(param[0], param[1]);
} else {
System.err.println("2 parameters are required, e.g. textrepl=a,b");
return;
}
} else {
fileList.add(args[i]);
}
}
file = new String[fileList.size()];
fileList.toArray(file);
} else {
file = new String[]{args[0]};
}
addexclusionTokenSet(reserved);
addexclusionTokenSet(builtIn);
JSO obfuscator = new JSO(file, destinationDir, stringObfuscationParameter);
obfuscator.run();
}
private static void printUsage() {
System.err.println("Usage: java JSO <list of javascript file> [options]");
System.err.println("");
System.err.println("where the options are:");
System.err.println("\te=<exception list file>");
System.err.println("\t\t- filename of the exception list");
System.err.println("\t\t- exception tokens are delimited by tab, space, dot, comma, ");
System.err.println("\t\t single quote and double quote");
System.err.println("\td=<destination directory>");
System.err.println("\t\t- the output directory");
System.err.println("\t\t- print to the STDOUT if not specified");
System.err.println("\to=<obfuscation parameters of string literals>");
System.err.println("\t\t- If it is specified, the characters in string literals will be ");
System.err.println("\t\t encoded to either \\uXXXX (hexidemcial) or \\XXX (octal) format");
System.err.println("\t\t- The parameters are a 2 or 3 floating point values delimited ");
System.err.println(" by commas. e.g. 0.5,0.3 or 0.5,0.3,0.9");
System.err.println("\t\t- The values are ");
System.err.println("\t\t * probability to encode a string");
System.err.println("\t\t * probability to encode a character in a candidate string");
System.err.println("\t\t * probability to encode a character into \\uXXXX format");
System.err.println("\t\t- The last parameter is set to 0.5 if not specified");
System.err.println("");
System.err.println("Press Enter to read the examples...");
try{
System.in.read();
} catch (Exception e){}
System.err.println("Examples:");
System.err.println("");
System.err.println(" Obfuscate all scripts in the current directory and output to ./out directory:");
System.err.println("\tjava JSO *.js d=out");
System.err.println("");
System.err.println(" Pipe the STDOUT output to x.o.js:");
System.err.println("\tjava JSO x.js > x.o.js ");
System.err.println("");
System.err.println(" Merge a.js and b.js and pipe the merged output to script.js. Tokens in ");
System.err.println(" exception list, noReplace.txt will not be replaced:");
System.err.println("\tjava JSO a.js b.js e=noReplace.txt > script.js");
System.err.println("");
System.err.println(" Obfuscate the 100% of string literals, 68% of the characters will be encoded. ");
System.err.println(" 50% of the characters will be encoded as \\uXXXX format (default):");
System.err.println("\tjava JSO x.js o=1,0.68");
}
public JSO(String[] file, String destinationDir, double[] stringObfuscationParameter){
this.file = file;
this.destinationDir = destinationDir;
if (stringObfuscationParameter != null && stringObfuscationParameter.length >= 2) {
this.stringObfuscationParameter = stringObfuscationParameter;
}
}
public void run() throws IOException {
for (int i = 0; i < file.length; i++) {
BufferedReader in = new BufferedReader(new FileReader(file[i]));
PrintWriter out = null;
File f = new File(file[i]);
if (destinationDir == null) {
out = new PrintWriter(System.out, true);
} else {
out = new PrintWriter(new FileWriter(new File(destinationDir + File.separator + f.getName())));
}
this.obfuscate(in, out, f.getName());
System.out.println("obfuscated " + f.getName());
in.close();
out.flush();
out.close();
}
System.err.println( "Obfuscated" );
System.err.println(map.toString().replace(',', '\n'));
encounteredInStrings.retainAll(map.keySet());
System.err.println( "Not Obfuscated in strings:" );
for( Iterator it = encounteredInStrings.iterator(); it.hasNext(); ) {
String s = (String)it.next();
System.err.println( "\t"+s+": " + (String)encounteredInStringsFiles.get(s) );
}
}
private void obfuscate(BufferedReader in, PrintWriter out, String fname) throws IOException {
state.reset();
int line_counter = 0;
for (String line = in.readLine(); line != null; line = in.readLine()) {
line_counter++;
if( !isDebug )
line = line.trim();
if (line.length() == 0) {
if( isDebug )
out.println();
continue;
}
if( line.startsWith( "//-" ) ) {
String[] toAdd = line.substring(3).split(",");
for( int i = 0; i < toAdd.length; i++ )
exclusionTokenSet.add(toAdd[i].trim());
continue;
} else if( line.startsWith("//+")) {
String[] toAdd = line.substring(3).split(",");
for( int i = 0; i < toAdd.length; i++ )
forceReplace.add(toAdd[i].trim());
continue;
} else if( line.startsWith("//'")) {
String[] toAdd = line.substring(3).split(",");
for( int i = 0; i < toAdd.length; i++ ) {
forceReplace.add(toAdd[i].trim());
forceReplaceInStrings.add(toAdd[i].trim());
}
}
for( Iterator it = forceTextualReplace.keySet().iterator(); it.hasNext(); ) {
String key = (String)it.next();
line = line.replaceAll(key, (String)forceTextualReplace.get(key));
}
StringTokenizer st = new StringTokenizer(line, delimiter, true);
if (st.hasMoreTokens()) {
state.setToken(st.nextToken());
}
for (; state.token != null; state.skipToken()) {
if (st.hasMoreTokens()) {
state.setNextToken(st.nextToken());
} else {
state.noToken();
}
boolean doubleSlashed = state.flipFlags();
if (doubleSlashed) {
break;
}
handleToken(out, fname, line_counter);
}
if( isDebug )
out.println();
else if (!state.delimiter && !state.commented )
out.print(" ");
}
}
private void handleToken(PrintWriter out, String fname, int line ) {
if (state.token.length() > 0) {
if (state.delimiter) {
if (state.inString() && !state.backslashed && state.c != '\\' &&
state.c != '\"' && state.c != '\'') {
state.token = obfuscateQuotedString(state.token);
}
} else {
if (state.inString()) {
if( forceReplaceInStrings.contains(state.token) && canReplace(state.token) ) {
state.token = generateToken(state.token);
} else if( Character.isJavaIdentifierStart(state.token.charAt(0))) {
encounteredInStrings.add(state.token);
String s = (String)encounteredInStringsFiles.get(state.token);
s = ( s == null ) ? "" : s + ", ";
s += fname +"[" + line + "]";
encounteredInStringsFiles.put(state.token, s);
}
if (!state.backslashed) {
state.token = obfuscateQuotedString(state.token);
}
} else if( !state.commented ) {
if(canReplace(state.token)){
state.token = generateToken(state.token);
} else if( state.token.length() > 0 && Character.isDigit( state.token.charAt(0) ) ) {
try {
int i = Integer.parseInt( state.token );
double res = randomizer.nextDouble();
int e = (int)(i * res);
if( i > 3 ) {
if( res < 0.2 && i >= 16 )
state.token = "0x"+Integer.toHexString(i);
else if( res < 0.6 && i >= 8 )
state.token = "0" + Integer.toOctalString(i);
else
state.token = "(" + e + "+" + (i-e) + ")";
}
} catch( NumberFormatException ex ) {
}
}
}
}
}
if (!state.commented && (state.printToken || state.inString())) {
out.print(state.token);
}
if (state.c == '}' && !state.commented && !isDebug) {
out.print(" ");
}
}
private static void readexclusionTokenSet(String file) throws IOException {
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(file));
for (String line = in.readLine(); line != null; line = in.readLine()) {
StringTokenizer st = new StringTokenizer(line, "\t ,.\"\'");
for (; st.hasMoreTokens();) {
exclusionTokenSet.add(st.nextToken());
}
}
} finally {
if (in != null) {
in.close();
}
}
}
private String obfuscateQuotedString(String token) {
if (randomizer.nextDouble() < stringObfuscationParameter[0]) {
StringBuffer buffer = new StringBuffer(token.length());
int n = token.length();
int pos = 0;
for (int i = 0; i < n; i++) {
if (randomizer.nextDouble() < stringObfuscationParameter[1]) {
buffer.append(token.substring(pos, i));
encode(token.charAt(i), buffer);
pos = i + 1;
}
}
if (pos < n) {
buffer.append(token.substring(pos));
}
return buffer.toString();
} else {
return token;
}
}
private void encode(char c, StringBuffer buffer) {
if (randomizer.nextDouble() < stringObfuscationParameter[2] || c > 0777) {
buffer.append("\\u");
encode(c, 16, 4, buffer);
} else {
buffer.append("\\");
encode(c, 8, 3, buffer);
}
}
private void encode(char c, int radix, int length, StringBuffer buffer) {
String value = Integer.toString(c, radix);
int n = length - value.length();
if (n > 0) {
for (int i = 0; i < n; i++) {
buffer.append('0');
}
buffer.append(value);
} else {
buffer.append(value.substring(-n));
}
}
private static String generateToken(String token) {
if (map.containsKey(token)) {
return (String) map.get(token);
} else {
String result = null;
do {
StringBuffer buffer = new StringBuffer(token.length());
for (int i = ref; i > 0; i = i / alpha.length) {
buffer.append(alpha[i % alpha.length]);
}
ref++;
result = buffer.toString();
} while (exclusionTokenSet.contains(result) || map.containsValue(result));
map.put(token, result);
return result;
}
}
private static boolean canReplace(String token) {
if (token.length() <= 1 || token.charAt(0) == '$' )
return false;
if (map.containsKey(token))
return true;
if( isExcludeAll )
return false;
if( forceReplace.contains(token) )
return true;
if (exclusionTokenSet.contains(token) )
return false;
if (Character.isDigit(token.charAt(0)))
return false;
if( token.charAt(0) == '_' )
return true;
return true;
}
private static void addexclusionTokenSet(String[] array) {
if (array != null) {
for (int i = 0; i < array.length; i++) {
if( exclusionTokenSet.contains(array[i]) )
System.err.println( "warn, already excluded: " + array[i] );
exclusionTokenSet.add(array[i]);
}
}
}
public static boolean isDelimiter(String token) {
if (token != null && token.length() > 0) {
for (int i = 0; i < DELIMITER.length; i++) {
if (token.charAt(0) == DELIMITER[i]) {
return true;
}
}
}
return false;
}
}
class JSOState {
boolean dotted = false;
boolean doubleQuoted = false;
boolean singleQuoted = false;
boolean backslashed = false;
boolean commented = false;
boolean printToken = true;
boolean delimiter = false;
String token;
String lastToken;
String nextToken;
char c0 = 0;
char c = 0;
char c2 = 0;
void reset() {
dotted = false;
doubleQuoted = false;
singleQuoted = false;
backslashed = false;
commented = false;
printToken = true;
delimiter = false;
token = null;
lastToken = null;
nextToken = null;
c0 = 0;
c = 0;
c2 = 0;
}
boolean printable() {
return !commented && (printToken || inString());
}
boolean inString() {
return doubleQuoted || singleQuoted;
}
boolean delimiterSurrounded() {
return !JSO.isDelimiter(nextToken) && !JSO.isDelimiter(lastToken);
}
boolean isWhitespace(){
return Character.isWhitespace(c);
}
String setToken(String value) {
String oldToken = lastToken;
lastToken = token;
token = value;
nextToken = null;
if (value != null) {
c0 = c;
c = token == null ? 0 : token.charAt(0);
c2 = 0;
backslashed = c0 == '\\';
dotted = c0 == '.';
delimiter = JSO.isDelimiter(token);
printToken = true;
}
return oldToken;
}
String tokenBackslashed() {
String result = null;
int index = 0;
if (c == 'u') {
index = 4;
} else if (Character.isDigit(c)) {
index = 3;
} else {
throw new IllegalStateException("Token not backslashed or invalid JavaScript syntax.");
}
result = token.substring(0, index);
token = token.substring(index);
return result;
}
void setNextToken(String value) {
nextToken = value;
c2 = value.charAt(0);
}
void skipToken() {
this.setToken(nextToken);
}
void noToken() {
nextToken = null;
c2 = 0;
}
boolean flipFlags() {
if (isWhitespace()) {
printToken = delimiterSurrounded() || JSO.isDebug;
} else if (c == '/') {
if (!commented && c2 == '/') {
return true;
} else if (!commented && c2 == '*' &&
!inString()) {
commented = true;
} else if (commented && c0 == '*') {
commented = false;
printToken = false;
}
} else if (c == '\"' && !singleQuoted && !backslashed && !commented) {
doubleQuoted = !doubleQuoted;
} else if (c == '\'' && !doubleQuoted && !backslashed && !commented) {
singleQuoted = !singleQuoted;
}
return false;
}
}

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project [<!ENTITY buildfile SYSTEM "file:./build-user.xml">]>
<project basedir="." default="update" name="Obfuscator">
<property name="obfuscator.location" value="." />
<property name="webim.location" value="../webim" />
<target name="update" depends="build">
<java classname="JSO" fork="true" error="${obfuscator.location}/bin/obfuscation.log">
<arg value="${obfuscator.location}/common.js" />
<arg value="${obfuscator.location}/chat.js" />
<arg value="${obfuscator.location}/users.js" />
<arg value="${obfuscator.location}/brws.js" />
<arg value="d=${webim.location}/js/" />
<!-- <arg value="debug"/> -->
<!-- <arg value="debugnames"/> -->
<!-- <arg value="o=0,0"/> -->
<classpath>
<pathelement location="${obfuscator.location}/bin/" />
</classpath>
</java>
</target>
<target name="build" depends="init">
<javac destdir="${obfuscator.location}/bin" fork="false">
<src path="${obfuscator.location}" />
</javac>
</target>
<target name="init">
<mkdir dir="${obfuscator.location}/bin"/>
</target>
</project>

View File

@ -1,19 +1,16 @@
var FrameUtils = {
getDocument: function(frm) {
if (frm.contentDocument) {
return frm.contentDocument;
return frm.contentDocument;
} else if (frm.contentWindow) {
return frm.contentWindow.document;
} else if (frm.document) {
return frm.document;
} else {
alert( myRealAgent + ": cannot find document in frame " + frm);
//for( var a in frm )
// alert( a );
return null;
}
},
initFrame: function(frm) {
var doc = this.getDocument(frm);
doc.open();
@ -57,8 +54,11 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
this.setOptions(_options);
this._options.onComplete = this.requestComplete.bind(this);
this._options.onException = this.handleException.bind(this);
this._options.onTimeout = this.handleTimeout.bind(this);
this._options.timeout = 5000;
this.updater = {};
this.frequency = (this._options.frequency || 2);
this.lastupdate = 0;
this.cansend = true;
FrameUtils.initFrame(this._options.container);
if( this._options.message ) {
@ -70,9 +70,15 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
},
handleException: function(_request, ex) {
this.setStatus(ex.name + " occured: " + ex.message);
this.setStatus("offline, reconnecting");
this.stopUpdate();
this.timer = setTimeout(this.update.bind(this), this.frequency * 1000);
this.timer = setTimeout(this.update.bind(this), 1000);
},
handleTimeout: function(_request) {
this.setStatus("timeout, reconnecting");
this.stopUpdate();
this.timer = setTimeout(this.update.bind(this), 1000);
},
updateOptions: function(act) {
@ -82,9 +88,9 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
if( this._options.user )
this._options.parameters += "&user=true";
if( act == 'refresh' && this._options.message && this._options.message.value != '' )
this._options.parameters += "&typed=1";
this._options.parameters += "&typed=1";
},
enableInput: function(val) {
if( this._options.message )
this._options.message.disabled = !val;
@ -103,24 +109,26 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
},
requestComplete: function(_response) {
this.enableInput(true);
this.cansend = true;
var xmlRoot = Ajax.getXml(_response);
if( xmlRoot && xmlRoot.tagName == 'thread' ) {
this.updateContent( xmlRoot );
} else {
this.handleError(_response, xmlRoot, 'refresh messages failed');
}
try {
this.enableInput(true);
this.cansend = true;
var xmlRoot = Ajax.getXml(_response);
if( xmlRoot && xmlRoot.tagName == 'thread' ) {
this.updateContent( xmlRoot );
} else {
this.handleError(_response, xmlRoot, 'refresh messages failed');
}
} catch (e) {
}
this.timer = setTimeout(this.update.bind(this), this.frequency * 1000);
},
postMessage: function(msg) {
if( msg == "" || !this.cansend) {
return;
}
this.cansend = false;
this.stopUpdate();
if( msg == "" || !this.cansend) {
return;
}
this.cansend = false;
this.stopUpdate();
this.updateOptions("post");
var postOptions = {}.extend(this._options);
postOptions.parameters += "&message=" + encodeURIComponent(msg);
@ -137,10 +145,10 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
},
changeName: function(newname) {
new Ajax.Request(this._options.servl, {parameters:'act=rename&thread=' + (this._options.threadid || -1) +
new Ajax.Request(this._options.servl, {parameters:'act=rename&thread=' + (this._options.threadid || -1) +
'&token=' + (this._options.token || 0) + '&name=' + encodeURIComponent(newname)});
},
onThreadClosed: function(_response) {
var xmlRoot = Ajax.getXml(_response);
if( xmlRoot && xmlRoot.tagName == 'closed' ) {
@ -165,14 +173,14 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
showTyping: function(istyping) {
if( $("typingdiv") ) {
$("typingdiv").style.display=istyping ? 'inline' : 'none';
}
}
},
setupAvatar: function(avatar) {
var imageLink = NodeUtils.getNodeText(avatar);
if( this._options.avatar && this._options.user ) {
this._options.avatar.innerHTML = imageLink != ""
? "<img src=\""+Chat.webimRoot+"/images/free.gif\" width=\"7\" height=\"1\" border=\"0\" alt=\"\" /><img src=\""
this._options.avatar.innerHTML = imageLink != ""
? "<img src=\""+Chat.webimRoot+"/images/free.gif\" width=\"7\" height=\"1\" border=\"0\" alt=\"\" /><img src=\""
+imageLink+ "\" border=\"0\" alt=\"\"/>"
: "";
}
@ -186,7 +194,7 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
if( _lastid ) {
this._options.lastid = _lastid;
}
var typing = NodeUtils.getAttrValue(xmlRoot, "typing");
if( typing ) {
this.showTyping(typing == '1');
@ -195,20 +203,34 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
for( var i = 0; i < xmlRoot.childNodes.length; i++ ) {
var node = xmlRoot.childNodes[i];
if( node.tagName == 'message' ) {
haveMessage = true;
haveMessage = true;
this.processMessage(result_div, node);
} else if( node.tagName == 'avatar' ) {
this.setupAvatar(node);
}
// TODO thread events
}
}
if( haveMessage ) {
if(window.location.search.indexOf('trace=on')>=0) {
var val = "updated";
if(this.lastupdate > 0) {
var seconds = ((new Date()).getTime() - this.lastupdate)/1000;
val = val + ", " + seconds + " secs";
if(seconds > 10) {
alert(val);
}
}
this.lastupdate = (new Date()).getTime();
this.setStatus(val);
} else {
this.clearStatus();
}
if( haveMessage ) {
FrameUtils.scrollDown(this._options.container);
if( !this.focused )
if( !this.focused ) {
window.focus();
}
}
},
handleKeyDown: function(k) {
if( k ){ ctrl=k.ctrlKey;k=k.which; } else { k=event.keyCode;ctrl=event.ctrlKey; }
if( this._options.message && ((k==13 && (ctrl || myRealAgent == 'opera')) || (k==10)) ) {
@ -226,19 +248,26 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
if( xmlRoot && xmlRoot.tagName == 'error' ) {
this.setStatus(NodeUtils.getNodeValue(xmlRoot,"descr"));
} else {
this.setStatus(_action+', ' + Ajax.getError(_response));
}
this.setStatus("reconnecting");
}
},
showStatusDiv: function(k) {
if( $("engineinfo") ) {
$("engineinfo").style.display='inline';
$("engineinfo").innerHTML = k;
}
},
setStatus: function(k) {
if( this.statusTimeout )
clearTimeout(this.statusTimeout);
window.status = k;
this.showStatusDiv(k);
this.statusTimeout = setTimeout(this.clearStatus.bind(this), 4000);
},
clearStatus: function() {
window.status = "";
$("engineinfo").style.display='none';
}
});
@ -246,7 +275,7 @@ Class.inherit( Ajax.ChatThreadUpdater, Ajax.Base, {
HSplitter = Class.create();
HSplitter.prototype = {
initialize: function(_options) {
this._options = _options;
this._options = _options;
this.captured = 0;
if( this._options.first && this._options.second && this._options.control ) {
this._options.control.onmousedown = this.onmousedownEvent.bind(this);
@ -255,7 +284,7 @@ HSplitter.prototype = {
}
},
onmousedownEvent: function(e) {
onmousedownEvent: function(e) {
var ev = e || event;
if( this._options.control.setCapture )
@ -294,13 +323,14 @@ HSplitter.prototype = {
var Chat = {
threadUpdater : {},
hSplitter : {},
applyName: function() {
Chat.threadUpdater.changeName($('uname').value);
$('changename1').style.display='none';
$('changename2').style.display='inline';
$('unamelink').innerHTML=$('uname').value;
},
showNameField: function() {
$('changename1').style.display='inline';
$('changename2').style.display='none';
@ -323,7 +353,7 @@ Behaviour.register({
'select#predefined' : function(el) {
el.onchange = function() {
var message = $('msgwnd');
message.value = this.options[this.selectedIndex].innerText || this.options[this.selectedIndex].innerHTML;
message.value = this.options[this.selectedIndex].innerText || this.options[this.selectedIndex].innerHTML;
this.selectedIndex = 0;
message.focus();
};
@ -350,7 +380,7 @@ Behaviour.register({
},
'a#refresh' : function(el) {
el.onclick = function() {
Chat.threadUpdater.stopUpdate();
Chat.threadUpdater.stopUpdate();
Chat.threadUpdater.update();
};
},
@ -365,4 +395,4 @@ EventHelper.register(window, 'onload', function(){
Chat.webimRoot = threadParams.wroot;
Chat.hSplitter = new HSplitter({control:$("spl1"), first:$("msgwndtd"), second:$("chatwndtd"), minfirst:30, minsec:30});
Chat.threadUpdater = new Ajax.ChatThreadUpdater(({container:myRealAgent=='safari'?self.frames[0]:$("chatwnd"),avatar:$("avatarwnd"),message:$("msgwnd")}).extend( threadParams || {} ));
});
});

View File

@ -17,7 +17,7 @@
var Class = {
create: function() {
return function() {
return function() {
this./**/initialize./**/apply(this, arguments);
};
},
@ -92,10 +92,10 @@ PeriodicalExecuter.prototype = {
onTimerEvent: function() {
if (!this.currentlyExecuting) {
try {
try {
this.currentlyExecuting = true;
this.callback();
} finally {
this.callback();
} finally {
this.currentlyExecuting = false;
}
}
@ -115,7 +115,7 @@ function findObj( id )
if( x.length == 0 ) return null;
if( x.length == 1 ) return x[ 0 ];
}
return x;
}
@ -136,7 +136,7 @@ function $() {
if (typeof elem == 'string')
elem = findObj(elem);
if (arguments.length == 1)
if (arguments.length == 1)
return elem;
elems.push(elem);
@ -150,15 +150,15 @@ if (!Function.prototype.apply) {
var parameterStrings = new Array();
if (!obj) obj = window;
if (!params) params = new Array();
for (var i = 0; i < params.length; i++)
parameterStrings[i] = 'params[' + i + ']';
obj.$apply$ = this;
var result = eval('obj.$apply$(' +
var result = eval('obj.$apply$(' +
parameterStrings.join(', ') + ')');
obj.$apply$ = null;
return result;
};
}
@ -174,7 +174,7 @@ var Ajax = {
getXml: function(_response) {
if( _response &&
_response.status >= 200 &&
_response.status >= 200 &&
_response.status < 300 ) {
var xmlDoc = _response.responseXML;
if( xmlDoc && xmlDoc.documentElement )
@ -182,7 +182,7 @@ var Ajax = {
}
return null;
},
getError: function(_response) {
return _response.statusText || "connection error N" + _response.status;
},
@ -200,10 +200,15 @@ Ajax.Base.prototype = {
}.extend(_options || {});
},
getStatus: function() {
try {
return this.transport.status || 0;
} catch (e) { return 0 }
},
responseIsSuccess: function() {
return this./**/transport.status == undefined
|| this.transport.status == 0
|| (this.transport.status >= 200 && this.transport.status < 300);
var status = this.getStatus();
return !status || (status >= 200 && status < 300);
},
responseIsFailure: function() {
@ -212,13 +217,15 @@ Ajax.Base.prototype = {
};
Ajax./**/Request = Class.create();
Ajax.Request./**/Events =
Ajax.Request./**/Events =
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
Class.inherit( Ajax.Request, Ajax.Base, {
initialize: function(url, _options) {
this.transport = Ajax.getTransport();
this.setOptions(_options);
this.transportTimer = {};
this.finished = false;
this.request(url);
},
@ -230,11 +237,13 @@ Class.inherit( Ajax.Request, Ajax.Base, {
if (this._options._method == 'get' && parameters.length > 0)
url += '?' + parameters;
this.transport.open(this._options._method, url, this._options.asynchronous);
this.transport.open(this._options._method.toUpperCase(), url, this._options.asynchronous);
if (this._options.asynchronous) {
this.transport.onreadystatechange = this.onStateChange.bind(this);
setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
if(this._options.timeout) {
this.transportTimer = setTimeout(this.handleTimeout.bind(this), this._options.timeout);
}
}
this.setRequestHeaders();
@ -248,18 +257,19 @@ Class.inherit( Ajax.Request, Ajax.Base, {
},
setRequestHeaders: function() {
var requestHeaders =
var requestHeaders =
['X-Requested-With', 'XMLHttpRequest'];
if (this._options._method == 'post') {
requestHeaders.push('Content-type',
requestHeaders.push('Content-type',
'application/x-www-form-urlencoded');
/* Force "Connection: close" for Mozilla browsers to work around
* a bug where XMLHttpReqeuest sends an incorrect Content-length
* header. See Mozilla Bugzilla #246651.
/* Force "Connection: close" for older Mozilla browsers to work
* around a bug where XMLHttpRequest sends an incorrect
* Content-length header. See Mozilla Bugzilla #246651.
*/
if (this.transport.overrideMimeType)
if (this.transport.overrideMimeType &&
(navigator.userAgent.match("/Gecko\/(\d{4})/") || [0,2005])[1] < 2005)
requestHeaders.push('Connection', 'close');
}
@ -276,18 +286,10 @@ Class.inherit( Ajax.Request, Ajax.Base, {
this.respondToReadyState(this.transport.readyState);
},
header: function(name) {
try {
return this.transport.getResponseHeader(name);
} catch (e) {}
},
evalResponse: function() {
try {
return eval(this.transport.responseText);
} catch (e) {
this.dispatchException(e);
}
handleTimeout: function() {
if(this.finished) { return; }
this.finished = true;
(this._options.onTimeout || Ajax.emptyFunction)(this);
},
respondToReadyState: function(readystate) {
@ -295,26 +297,18 @@ Class.inherit( Ajax.Request, Ajax.Base, {
if (event == 'Complete') {
try {
(this._options['on' + this.transport.status]
|| this._options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
|| Ajax.emptyFunction)(this.transport);
if(!this.finished) {
this.finished = true;
if(this._options.timeout) { clearTimeout(this.transportTimer); }
(this._options.onComplete || Ajax.emptyFunction)(this.transport);
}
} catch (e) {
this.dispatchException(e);
}
if ((this.header('Content-type') || '').match("text\\/javascript"))
this.evalResponse();
}
try {
(this._options['on' + event] || Ajax.emptyFunction)(this.transport);
} catch (e) {
this.dispatchException(e);
}
/* Avoid memory leak in MSIE: clean up the oncomplete event handler */
if (event == 'Complete')
/* Avoid memory leak in MSIE: clean up the oncomplete event handler */
this.transport.onreadystatechange = Ajax.emptyFunction;
}
},
dispatchException: function(exception) {
@ -325,7 +319,7 @@ Class.inherit( Ajax.Request, Ajax.Base, {
var EventHelper = {
register : function(obj, ev,func){
var oldev = obj[ev];
if (typeof oldev != 'function') {
obj[ev] = func;
} else {
@ -341,7 +335,7 @@ var EventHelper = {
Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work
of Simon Willison (see comments by Simon below).
http://ripcord.co.nz/behaviour/
*/
*/
var Behaviour = {
list : new Array,
@ -436,11 +430,11 @@ document.getElementsBySelector = function(selector) {
}
// [evgeny] code for attribute selection is removed...
if (!currentContext[0]){
return;
}
// If we get here, token is JUST an element (not a class or ID selector)
tag_name = token;
var found = new Array;
@ -492,14 +486,14 @@ var CommonUtils = {
return _row;
if( _table.rows['head'] != null )
return null;
for( k=0; k < _table.rows.length; k++ ) {
if( _table.rows[k].id == _id )
return _table.rows[k];
}
return null;
return null;
},
getCell: function(_id,_row,_table) {
var _cell = _row.cells[_id];
if( _cell != null )
@ -510,9 +504,9 @@ var CommonUtils = {
if( _row.cells[k].id == _id )
return _row.cells[k];
}
return null;
return null;
},
insertCell: function(_row,_id,_className,_align,_height, _inner) {
var cell = _row.insertCell(-1);
cell.id = _id;
@ -524,3 +518,4 @@ var CommonUtils = {
cell.innerHTML = _inner;
}
};

View File

@ -5,16 +5,25 @@ Class.inherit( Ajax.PeriodicalUpdater, Ajax.Base, {
this.setOptions(_options);
this._options.onComplete = this.requestComplete.bind(this);
this._options.onException = this.handleException.bind(this);
this._options.onTimeout = this.handleTimeout.bind(this);
this._options.timeout = 5000;
this.frequency = (this._options.frequency || 2);
this.updater = {};
this.update();
},
handleException: function(_request, ex) {
if( this._options.handleError )
this._options.handleError( ex.name + " occured: " + ex.message );
this._options.handleError("offline, reconnecting");
this.stopUpdate();
this.timer = setTimeout(this.update.bind(this), this.frequency * 1000);
this.timer = setTimeout(this.update.bind(this), 1000);
},
handleTimeout: function(_request) {
if( this._options.handleError )
this._options.handleError("timeout, reconnecting");
this.stopUpdate();
this.timer = setTimeout(this.update.bind(this), 1000);
},
stopUpdate: function() {
@ -30,14 +39,16 @@ Class.inherit( Ajax.PeriodicalUpdater, Ajax.Base, {
},
requestComplete: function(presponse) {
if (presponse != null && presponse.status == 200 ) {
var xmlDoc = presponse.responseXML;
(this._options.updateContent || Ajax.emptyFunction)( xmlDoc );
} else {
if( this._options.handleError )
this._options.handleError(Ajax.getError(_response));
try {
var xmlRoot = Ajax.getXml(presponse);
if( xmlRoot ) {
(this._options.updateContent || Ajax.emptyFunction)( xmlRoot );
} else {
if( this._options.handleError )
this._options.handleError("reconnecting");
}
} catch(e) {
}
this.timer = setTimeout(this.update.bind(this), this.frequency * 1000);
}
});
@ -49,13 +60,13 @@ var HtmlGenerationUtils = {
cell.style.backgroundImage = 'url('+webimRoot+'/images/tablediv3.gif)';
cell.innerHTML = '<img src="'+webimRoot+'/images/free.gif" width="3" height="1" border="0" alt="">';
},
removeHr: function(_table, _index ) {
_table.deleteRow(_index+2);
_table.deleteRow(_index+1);
_table.deleteRow(_index);
},
insertHr: function(_table, _index) {
var row = _table.insertRow(_index);
var cell = row.insertCell(-1);
@ -74,12 +85,12 @@ var HtmlGenerationUtils = {
cell.height = 2;
},
popupLink: function(link, title, wndid, inner, width, height) {
return '<a href="'+link+'" target="_blank" title="'+title+'" onclick="this.newWindow = window.open(\''+link+'\', \''+
popupLink: function(link, title, wndid, inner, width, height,linkclass) {
return '<a href="'+link+'"'+(linkclass != null ? ' class="'+linkclass+'"' : '')+' target="_blank" title="'+title+'" onclick="this.newWindow = window.open(\''+link+'\', \''+
wndid+'\', \'toolbar=0,scrollbars=0,location=0,status=1,menubar=0,width='+width+',height='+height+',resizable=1\');this.newWindow.focus();this.newWindow.opener=window;return false;">'+
inner+'</a>';
},
generateOneRowTable: function(content) {
return '<table width="100%" cellspacing="0" cellpadding="0" border="0"><tr>' + content + '</tr></table>';
},
@ -87,21 +98,18 @@ var HtmlGenerationUtils = {
viewOpenCell: function(username,servlet,id,canview,canopen,ban,message) {
var cellsCount = 2;
var link = servlet+"?thread="+id;
var innerContent = ( ban == "full" ) ? "<i style='color:#aaaaaa;'>"+username+"</i>" : ( ( ban == "other" ) ? "<i>"+username+"</i>" : username );
var gen = '<td class="table" style="padding-left:0px; padding-right:0px;">';
gen += HtmlGenerationUtils.popupLink( canopen ? link : link+"&viewonly=true", localized[canopen ? 0 : 1], "ImCenter"+id, innerContent, 600, 420);
gen += HtmlGenerationUtils.popupLink( link, localized[canopen ? 0 : 1], "ImCenter"+id, username, 600, 420, ban);
gen += '</td><td><img src="'+webimRoot+'/images/free.gif" width="5" height="1" border="0" alt=""></td>';
if( canopen ) {
gen += '<td width="30" align="center">';
gen += HtmlGenerationUtils.popupLink( link, localized[0], "ImCenter"+id, '<img src="'+webimRoot+'/images/tbliclspeak.gif" width="15" height="15" border="0" alt="'+localized[0]+'">', 600, 420);
gen += HtmlGenerationUtils.popupLink( link, localized[0], "ImCenter"+id, '<img src="'+webimRoot+'/images/tbliclspeak.gif" width="15" height="15" border="0" alt="'+localized[0]+'">', 600, 420, null);
gen += '</td>';
cellsCount++;
}
return HtmlGenerationUtils.generateOneRowTable(gen);
}
};
Ajax.ThreadListUpdater = Class.create();
@ -118,22 +126,22 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
this.t = this._options.table;
this.periodicalUpdater = new Ajax.PeriodicalUpdater(this._options);
},
updateParams: function() {
return "company=" + this._options.company + "&since=" + this._options.lastrevision;
},
setStatus: function(msg) {
this._options.status.innerHTML = msg;
},
handleError: function(s) {
this.setStatus( s );
},
updateThread: function(node) {
var id, stateid, vstate, canview = false, canopen = false, ban = null;
for( var i = 0; i < node.attributes.length; i++ ) {
var attr = node.attributes[i];
if( attr.nodeName == "id" )
@ -144,15 +152,15 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
vstate = attr.nodeValue;
else if( attr.nodeName == "canopen" )
canopen = true;
}
function setcell(_table, row,id,pcontent) {
var cell = CommonUtils.getCell( id, row, _table );
if( cell )
cell.innerHTML = pcontent;
}
var row = CommonUtils.getRow("thr"+id, this.t);
if( stateid == "closed" ) {
if( row ) {
@ -169,13 +177,12 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
var agent = NodeUtils.getNodeValue(node,"agent");
var modified = NodeUtils.getNodeValue(node,"modified");
var message = NodeUtils.getNodeValue(node,"message");
var etc = "";
var etc = '<td class="table">'+NodeUtils.getNodeValue(node,"useragent")+'</td>';
etc = HtmlGenerationUtils.generateOneRowTable(etc);
var startRow = CommonUtils.getRow(stateid, this.t);
var endRow = CommonUtils.getRow(stateid+"end", this.t);
if( row != null && (row.rowIndex <= startRow.rowIndex || row.rowIndex >= endRow.rowIndex ) ) {
HtmlGenerationUtils.removeHr(this.t, row.rowIndex+1);
this.t.deleteRow(row.rowIndex);
@ -187,7 +194,7 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
HtmlGenerationUtils.insertHr(this.t, startRow.rowIndex+2);
row.id = "thr"+id;
this.threadTimers[id] = new Array(vtime,modified,stateid);
CommonUtils.insertCell(row, "name", "table", null, 30, HtmlGenerationUtils.viewOpenCell(vname,this._options.agentservl,id,canview,canopen,ban,message) );
CommonUtils.insertCell(row, "name", "table", null, 30, HtmlGenerationUtils.viewOpenCell(vname,this._options.agentservl,id,canview,canopen,ban,message));
HtmlGenerationUtils.insertSplitter(row);
CommonUtils.insertCell(row, "contid", "table", "center", null, vaddr );
HtmlGenerationUtils.insertSplitter(row);
@ -200,7 +207,7 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
CommonUtils.insertCell(row, "wait", "table", "center", null, (stateid!='chat' ? this.getTimeSince(modified) : '-') );
HtmlGenerationUtils.insertSplitter(row);
CommonUtils.insertCell(row, "etc", "table", "center", null, etc );
if( stateid == 'wait' || stateid == 'prio' )
return true;
} else {
@ -215,7 +222,7 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
}
return false;
},
updateQueueMessages: function() {
function updateQueue(t,id,nclients) {
var startRow = t.rows[id];
@ -228,12 +235,12 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
_status.innerHTML = (startRow.rowIndex + 1 == endRow.rowIndex) ? nclients : "";
_status.height = (startRow.rowIndex + 1 == endRow.rowIndex) ? 30 : 10;
}
updateQueue(this.t, "wait", this._options.noclients);
updateQueue(this.t, "prio", this._options.noclients);
updateQueue(this.t, "chat", this._options.noclients);
},
getTimeSince: function(srvtime) {
var secs = Math.floor(((new Date()).getTime()-srvtime-this.delta)/1000);
var minutes = Math.floor(secs/60);
@ -251,7 +258,7 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
return prefix + minutes+":"+secs;
},
updateTimers: function() {
for (var i in this.threadTimers) {
if (this.threadTimers[i] != null) {
@ -269,19 +276,18 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
}
}
},
updateContent: function(xmldoc) {
var root = xmldoc.documentElement;
updateContent: function(root) {
var newAdded = false;
if( root.tagName == 'threads' ) {
var _time = NodeUtils.getAttrValue(root, "time");
var _revision = NodeUtils.getAttrValue(root, "revision" );
if( _time )
this.delta = (new Date()).getTime() - _time;
if( _revision )
this._options.lastrevision = _revision;
for( var i = 0; i < root.childNodes.length; i++ ) {
var node = root.childNodes[i];
if( node.tagName == 'thread' )
@ -291,12 +297,13 @@ Class.inherit( Ajax.ThreadListUpdater, Ajax.Base, {
this.updateQueueMessages();
this.updateTimers();
this.setStatus( "Up to date" );
if( newAdded )
if( newAdded ) {
window.focus();
}
} else if( root.tagName == 'error' ) {
this.setStatus( "error: " + NodeUtils.getNodeValue(root,"descr") );
this.setStatus(NodeUtils.getNodeValue(root,"descr") );
} else {
this.setStatus( "wrong response" );
this.setStatus( "reconnecting" );
}
}
});
@ -305,6 +312,5 @@ var webimRoot = "";
EventHelper.register(window, 'onload', function(){
webimRoot = updaterOptions.wroot;
new Ajax.ThreadListUpdater(({table:$("threadlist"),status:$("connstatus")}).extend(updaterOptions || {}));
new Ajax.ThreadListUpdater(({table:$("threadlist"),status:$("connstatus")}).extend(updaterOptions || {}));
});