/*
	@TITLE
		Verwaltung für Web-Bugs
	
	@DESCRIPTION
		Dieses Script dient der Übertragung einzelner
		Web-Bugs an den Web-Server
	
	@AUTHOR
		Timo Paulwitz
	
	@COPYRIGHT
		Copyright © 2005 by CHAMAELEON AG (http://www.chamaeleon.de)
*/


/*
	Setze auf oberster Ebene eine window-Id, um die aktuelle Session
	zu verfolgen. Je nach Browser-Einstellung (z.B. protected Attribute in Opera 8.0)
	kann einem Fenster untersagt sein, auf oberster Ebene Fensterattribute zu setzen.
	In diesem Falle wird einfach davon ausgegangen, dass das Fenster seine ID selbst setzen
	kann.
*/


/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var CHAMAELEON_WEBBUG_reciever = "/_scripts/webBug.fcgi";
var CHAMAELEON_WEBBUG_dwellSpan = 60000;
var CHAMAELEON_WEBBUG_chunkSize = 800; 




var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

window["CHAMAELEON_WEBBUG_lastTransfer"] = 0;
var CHAMAELEON_WEBBUG_windowId = (Math.floor((new Date()).getTime() /86400000) *  86400000).toString(36);
var CHAMAELEON_WEBBUG_bugCounter = 0;
function get_cookie(name) { 
	var value=null; 
	if(document.cookie != "") { 
		var kk=document.cookie.indexOf(name+"="); 
		if(kk >= 0) { 
			kk=kk+name.length+1; 
			var ll=document.cookie.indexOf(";", kk); 
			if(ll < 0)ll=document.cookie.length; 
			value=document.cookie.substring(kk, ll); 
			value=unescape(value); 
		} 
	}
	return value;
}
function CHAMAELEON_WEBBUG_storeSessionId(){
	document.cookie = "WebBugWindowId=" + CHAMAELEON_WEBBUG_windowId + ";path=/";
}
function CHAMAELEON_WEBBUG_fetchSessionId(){
	var windowId = get_cookie("WebBugWindowId");
	if (windowId && windowId != ""){
		CHAMAELEON_WEBBUG_windowId = windowId;
	} else {
		windowId = (new Date()).getTime().toString(36);
		/* Testweise Cookie setzen */
		var recoverId = CHAMAELEON_WEBBUG_windowId;
		CHAMAELEON_WEBBUG_windowId = windowId;
		CHAMAELEON_WEBBUG_storeSessionId();
		if (get_cookie("WebBugWindowId") != windowId){
			windowId = recoverId;
		}
	}
	document.cookie = "WebBugWindowId=;path=/";
	window.onunload = CHAMAELEON_WEBBUG_storeSessionId;
	return windowId;
}


if (window == top){
	if (navigator.cookieEnabled){
		CHAMAELEON_WEBBUG_windowId = CHAMAELEON_WEBBUG_fetchSessionId();	
	}
}

function CHAMAELEON_WEBBUG_collectData(win, windowPath, oldState){
	
	var k;
	var newState = new Object();
	
	newState["windowPath"] = windowPath;
	newState["location"] = win.location.href;
	
	if (newState["location"] == oldState["location"]){
		/* 
			Es gab keine Zustandsaenderung. Da es stellenweise zu Flakern auf Grund von
			Framegenerator-Aufrufen kommen kann, werden die vorherigen Daten 
			wiederhergestellt
		*/
		newState["referrer"] = oldState["referrer"];
		newState["callStart"] = oldState["callStart"];
		newState["ionasId"] = oldState["ionasId"];
	} else {
		if (win.document.referrer){
			newState["referrer"] = win.document.referrer;
		} else {
			newState["referrer"] = "";
		}
		newState["callStart"] = (new Date()).getTime();
		newState["ionasId"] = "";
		try {
			if (! win.document.ionasDocumentId){
				var meta = win.document.getElementsByTagName("meta");
				for (k=0; k < meta.length; k++){
					if (meta[k].getAttribute("name") == "ionasdocumentid"){
						newState["ionasId"] = meta[k].getAttribute("content");
					}
				}
			}
		} catch(e) {
		} finally {
		}
	}


	newState["innerData"] = windowPath
				+ "\t" + newState["callStart"]
				+ "\t" + newState["ionasId"]
				+ "\t" + newState["location"]
				+ "\t" + newState["referrer"]
				+ "\n";
	
	
	newState["subFrames"] = new Array();
	if (win.frames){
		for (k=0; k < win.frames.length; k++){
			var oldFrameState;
			if (oldState["subFrames"] && oldState["subFrames"][k]){
				oldFrameState = oldState["subFrames"][k];
			} else {
				oldFrameState = new Object();
			}
			try {
				var f = win.frames[k];
				if (f.name != "CHAMAELEON_WEBBUG_transferFrame"){
					newState["subFrames"][k] = CHAMAELEON_WEBBUG_collectData(f, windowPath + "." + k, oldFrameState);
					newState["innerData"] += newState["subFrames"][k]["innerData"];
				}
			} catch(e) {
			} finally {
			}
		}
	}
	return newState;
}


function CHAMAELEON_WEBBUG_getUserId(){	
	var userId = null;
	if (navigator.cookieEnabled){
		userId = get_cookie("WebBugUserId");
		if (! userId) {
			var newUserId = (new Date()).getTime().toString(36) + "_"; 
			while (newUserId.length <32){
				newUserId += Math.round(Math.random()*36).toString(36)
			}
			var expiration_date = new Date("January 1, 3000");
			expiration_date = expiration_date.toGMTString();
			document.cookie = "WebBugUserId=" + escape(newUserId) + ";path=/;expires=" + expiration_date;
			userId = get_cookie("WebBugUserId");
		}
	} 
	if (! userId){
		userId = "";	
	}
	return userId;
}

function CHAMAELEON_WEBBUG_transfer(){
	var now = (new Date()).getTime();
	try {
		top["CHAMAELEON_WEBBUG_lastTransfer"] = now;
	} catch(e) {
	}
	if (! window.top["CHAMAELEON_WEBBUG_HISTORY"]){
		window.top["CHAMAELEON_WEBBUG_HISTORY"] = new Object();
		
	}
	window.top["CHAMAELEON_WEBBUG_HISTORY"] = CHAMAELEON_WEBBUG_collectData(top, CHAMAELEON_WEBBUG_windowId, window.top["CHAMAELEON_WEBBUG_HISTORY"]);
	var testStr1 = "" + window.top["CHAMAELEON_WEBBUG_HISTORY"]["innerData"] + "";
	var testStr2 = escape(window.top["CHAMAELEON_WEBBUG_HISTORY"]["innerData"]) + "";
	if (testStr1 != unescape(testStr2)){
		alert("ERROR1");
	}
	if (escape(testStr1) != testStr2){
		alert("ERROR2");
	}
	
	var request = CHAMAELEON_WEBBUG_reciever
		+ "?timestamp=" + (new Date()).getTime()
		+ "&userid=" + CHAMAELEON_WEBBUG_getUserId()
		+ "&os=" + escape(navigator["platform"])
		+ "&browser=" + escape(navigator["appName"])
		+ "&language=" + escape(navigator["language"])
		+ "&availheight=" + escape(screen["availHeight"])
		+ "&availwidth=" + escape(screen["availWidth"])
		+ "&colordepth=" + escape(screen["colorDepth"])
		+ "&height=" + escape(screen["height"])
		+ "&width=" + escape(screen["width"])
		+ "&timezone=" + escape((new Date()).getTimezoneOffset())
		+ "&state=" + escape(window.top["CHAMAELEON_WEBBUG_HISTORY"]["innerData"]);
	CHAMAELEON_WEBBUG_submit(window, request);
}

var CHAMAELEON_WEBBUG_transferImages = new Array();
function CHAMAELEON_WEBBUG_submit(win, request){

	/*
		Falls auf irgendwie ein Transfer-Frame existiert nutze diesen zum
		übertragen der Daten
	*/
	if (win.frames && win.frames["CHAMAELEON_WEBBUG_transferFrame"]){
		win.frames["CHAMAELEON_WEBBUG_transferFrame"].location.href=request;
		return true;
	}

	if (win.frames){
		for (var k = 0; k < win.frames.length; k++){
			var f = win.frames[k];
			if (CHAMAELEON_WEBBUG_submit(f, request)){
				return true;
			}
		}
	}
	
	if (win.document && win.document.images){
		
		var d = request.split(/\?/);
		var data = d[1];
		var md5Sum = hex_md5(data);
		
		var chunkIdx = -1;
		var charVal  = "";
		var charIdx  = 0;
		var chunks = new Array();
		for (charIdx=0; charIdx < data.length; charIdx++){
			if (charIdx % CHAMAELEON_WEBBUG_chunkSize == 0){
				chunkIdx++;
				chunks[chunkIdx] = "";
			}
			charVal = data.charAt(charIdx);
			if (charVal == "_"){
				chunks[chunkIdx] += "__";
			} else if (charVal == "%"){
				chunks[chunkIdx] += "_0";
			} else if (charVal == "&"){
				chunks[chunkIdx] += "_1";
			} else if (charVal == "="){
				chunks[chunkIdx] += "_2";
			} else {
				chunks[chunkIdx] += charVal;
			}
			
		}

		var bugId = 
				(new Date()).getTime().toString(36) // Aktuelle Zeit
			+ "-" 
			+ (CHAMAELEON_WEBBUG_bugCounter++).toString(36)  // Fenster interner counter
			+ "-" 
			+ CHAMAELEON_WEBBUG_windowId // Fenster-Id
			+ "-" 
			+ Math.round(Math.random() * 0x7fffffff).toString(36); // 32-Bit Zufallsstring

		for (var idx=0; idx < chunks.length; idx++){
			var img = new Image();
			img.src = d[0] 
				+ "?id=" + bugId
				+ "&md5=" + md5Sum
				+ "&i=" + idx
				+ "&c=" + chunks.length
				+ "&d=" + chunks[idx];
			CHAMAELEON_WEBBUG_transferImages[CHAMAELEON_WEBBUG_transferImages.length] = img;
		}
		return true;

	} else {	
		return false;
	}
}

function CHAMAELEON_WEBBUG_autoTransfer(){
	top["CHAMAELEON_WEBBUG_autotransfering"] = true;
	var now = (new Date()).getTime();
	var nextTimeout = top["CHAMAELEON_WEBBUG_lastTransfer"] - now + CHAMAELEON_WEBBUG_dwellSpan;
	if (nextTimeout < 0){
		CHAMAELEON_WEBBUG_transfer();
		nextTimeout = CHAMAELEON_WEBBUG_dwellSpan;
	}
	
	top.setTimeout("CHAMAELEON_WEBBUG_autoTransfer()", nextTimeout);
}

if (window == top) {
	CHAMAELEON_WEBBUG_autoTransfer();
} else {
	try {
		top.CHAMAELEON_WEBBUG_transfer();
	} catch(e) {
		CHAMAELEON_WEBBUG_transfer();
	} finally {
	}
}







/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */


/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length
 */
function core_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);

}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Calculate the HMAC-MD5, of a key and some data
 */
function core_hmac_md5(key, data)
{
  var bkey = str2binl(key);
  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
  return core_md5(opad.concat(hash), 512 + 128);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert a string to an array of little-endian words
 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
 */
function str2binl(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  return bin;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2str(bin)
{
  var str = "";
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
  return str;
}

/*
 * Convert an array of little-endian words to a hex string.
 */
function binl2hex(binarray)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
  }
  return str;
}

/*
 * Convert an array of little-endian words to a base-64 string
 */
function binl2b64(binarray)
{
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i += 3)
  {
    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
    }
  }
  return str;
}

