Created
November 9, 2018 11:47
-
-
Save flamencist/58b74e57a3d3b3bbf95aaeb3ac008d8a to your computer and use it in GitHub Desktop.
implemented citrix receiver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function (window) { | |
'use strict'; | |
function EndOfLineFormatter() { | |
var os = { | |
ANDPHONE: 9, | |
ANDTAB: 6, | |
BLACKBERRY: 10, | |
IPAD: 5, | |
IPHONE: 8, | |
LINUX: 3, | |
MAC: 2, | |
NONSUPPORTEDOS: 7, | |
UNIX: 4, | |
WINDOWS: 1 | |
}; | |
var browsers = { | |
BB10: 5, | |
CHROME: 3, | |
EDGE: 8, | |
FIREFOX: 1, | |
MSIE: 2, | |
NONSUPPORTEDBROWSER: 6, | |
OTHERS: 7, | |
SAFARI: 4 | |
}; | |
function getSystemInfo() { | |
var systemInfo = {}; | |
systemInfo["browserVersion"] = null; | |
systemInfo["OS"] = null; | |
systemInfo["browserid"] = null; | |
systemInfo["isTouchOS"] = ("ontouchstart" in document.documentElement) ? true : false; | |
function getBrowserOs() { | |
if (navigator.appVersion.indexOf("Win") !== -1) { | |
return os["WINDOWS"]; | |
} | |
if (navigator.platform.indexOf("iPhone") !== -1) { | |
return os["IPHONE"]; | |
} | |
if (navigator.platform.indexOf("iPad") !== -1) { | |
return os["IPAD"]; | |
} | |
if (navigator.appVersion.indexOf("Mac") !== -1) { | |
return os["MAC"]; | |
} | |
if (navigator.appVersion.indexOf("X11") !== -1) { | |
return os["UNIX"]; | |
} | |
if (navigator.appVersion.indexOf("Linux") !== -1) { | |
return os["LINUX"]; | |
} | |
var userAgent = navigator.userAgent.toLowerCase(); | |
var isOtherPhone = (userAgent.indexOf("series60") !== -1) || (userAgent.indexOf("symbian") !== -1) || (userAgent.indexOf("windows ce") !== -1) || (userAgent.indexOf("blackberry") !== -1); | |
var orientationSupported = typeof orientation !== "undefined" ? true : false; | |
var touchSupported = ("ontouchstart" in document.documentElement) ? true : false; | |
if (navigator.platform.indexOf("BlackBerry") !== -1) { | |
return os["BLACKBERRY"]; | |
} | |
if ((userAgent.search("android") > -1) && !(userAgent.search("mobile") > -1)) { | |
return os["ANDTAB"]; | |
} | |
if (((userAgent.search("android") > -1) && (userAgent.search("mobile") > -1)) || (!isOtherPhone && touchSupported && orientationSupported)) { | |
return os["ANDPHONE"]; | |
} | |
return os["NONSUPPORTEDOS"]; | |
} | |
function getBrowserId() { | |
var userAgent = navigator.userAgent; | |
var browser = null; | |
var appVersion = '' + parseFloat(navigator.appVersion); | |
var indexOfName, indexOfAppVersionEnd; | |
if ((indexOfName = userAgent.indexOf("MSIE")) !== -1) { | |
browser = browsers["MSIE"]; | |
appVersion = userAgent.substring(indexOfName + 5); | |
} else if ((indexOfName = userAgent.indexOf("Edge")) !== -1) { | |
browser = browsers["EDGE"]; | |
appVersion = userAgent.substring(indexOfName + 5, indexOfName + 5 + 4); | |
} else if (userAgent.indexOf("Trident") !== -1) { | |
browser = browsers["MSIE"]; | |
indexOfName = userAgent.indexOf("rv:"); | |
appVersion = userAgent.substring(indexOfName + 3, indexOfName + 3 + 4); | |
} else if ((indexOfName = userAgent.indexOf("BB10")) !== -1) { | |
browser = browsers["BB10"]; | |
appVersion = userAgent.substring(indexOfName + 4); | |
if ((indexOfName = userAgent.indexOf("Version")) !== -1) appVersion = userAgent.substring(indexOfName + 8); | |
} else if ((indexOfName = userAgent.indexOf("Chrome")) !== -1) { | |
browser = browsers["CHROME"]; | |
appVersion = userAgent.substring(indexOfName + 7); | |
if ((indexOfName = userAgent.indexOf("Version")) !== -1) appVersion = userAgent.substring(indexOfName + 8); | |
} else if ((indexOfName = userAgent.indexOf("Safari")) !== -1) { | |
browser = browsers["SAFARI"]; | |
appVersion = userAgent.substring(indexOfName + 7); | |
if ((indexOfName = userAgent.indexOf("Version")) !== -1) appVersion = userAgent.substring(indexOfName + 8); | |
if (appVersion == "" && (indexOfName = userAgent.indexOf("AppleWebKit")) !== -1) appVersion = userAgent.substring(indexOfName + 12); | |
} else if ((indexOfName = userAgent.indexOf("Firefox")) !== -1) { | |
browser = browsers["FIREFOX"]; | |
appVersion = userAgent.substring(indexOfName + 8); | |
} else { | |
browser = browsers["NONSUPPORTEDBROWSER"]; | |
} | |
if ((indexOfAppVersionEnd = appVersion.indexOf(";")) !== -1) { | |
appVersion = appVersion.substring(0, indexOfAppVersionEnd); | |
} | |
if ((indexOfAppVersionEnd = appVersion.indexOf(" ")) !== -1) { | |
appVersion = appVersion.substring(0, indexOfAppVersionEnd); | |
} | |
systemInfo["browserVersion"] = parseInt('' + appVersion, 10); | |
if (isNaN(systemInfo["browserVersion"])) { | |
appVersion = '' + parseFloat(navigator.appVersion); | |
systemInfo["browserVersion"] = parseInt(navigator.appVersion, 10); | |
} | |
return browser; | |
} | |
systemInfo["browserid"] = getBrowserId(); | |
systemInfo["OS"] = getBrowserOs(); | |
return systemInfo; | |
} | |
var systemInfo = getSystemInfo(); | |
this.localToRemote = function (text) { | |
if (systemInfo["OS"] == os["WINDOWS"] && systemInfo["browserid"] != browsers["FIREFOX"]) { | |
return text; | |
} | |
var eol = "\n"; | |
var output = ""; | |
var prev = ""; | |
var cur; | |
var len = text.length; | |
for (var i = 0; i < len; i++) { | |
cur = text.charAt(i); | |
if (cur == "\n" && (i <= 0 || prev != "\r")) | |
output += eol; | |
else | |
output += cur; | |
prev = cur; | |
} | |
output += " "; | |
return output; | |
}; | |
this.remoteToLocal = function (text) { | |
if (systemInfo["OS"] == os["WINDOWS"]) { | |
return text; | |
} | |
var output = ""; | |
var len = text.length; | |
var prev = "", cur; | |
for (var i = 0; i < len; i++) { | |
cur = text.charAt(i); | |
if ((prev == "\r") && (cur == "\n")) { | |
output += cur; | |
prev = ""; | |
} else { | |
output += prev; | |
prev = cur; | |
} | |
} | |
output += prev; | |
return output; | |
}; | |
} | |
function ClipboardDataParser() { | |
function convertToBytes(src, arr, offset, length) { | |
for (var i = offset; i < length; i++) { | |
var code = src.charCodeAt(i); | |
arr[2 * i] = code & 255; | |
arr[2 * i + 1] = (code >> 8) & 255; | |
} | |
return arr; | |
} | |
function convertToString(src, len) { | |
var output = ""; | |
var firstByte, secondByte, cur; | |
var length = len; | |
if (!length) { | |
length = src.length; | |
} | |
for (var i = 0; i + 1 < length; i += 2) { | |
firstByte = src[i]; | |
secondByte = src[i + 1]; | |
cur = secondByte << 8 | firstByte; | |
output += String.fromCharCode(cur); | |
} | |
return output; | |
} | |
this.parse = function (data, remoteFormat, localFormat) { | |
if (localFormat == -1 && remoteFormat == 13) { | |
var text = convertToString(data, data.length); | |
if (text.length > 1 && text[text.length - 1] == " ") { | |
text = text.substr(0, text.length - 1); | |
} | |
return text; | |
} | |
if (localFormat == 13 && remoteFormat == -1) { | |
var bytes = convertToBytes(data, new Uint8Array(data.length * 2 + 2), 0, (data.length * 2)); | |
return bytes; | |
} | |
return ""; | |
}; | |
} | |
function CitrixClipboard(clipboardDataParser, endOfLineFormatter) { | |
var isStarted = false; | |
var timestamp = timeStamp(); | |
var currentData = {}; | |
var localTimestamp = -1; | |
var serverTimestamp = null; | |
var currentMessageData = { | |
"formatArray": null, | |
"len": -1, | |
"timestamp": -1, | |
"currentDataArray": null, | |
"formatname": null, | |
"pendingFormats": 0 | |
}; | |
var workerPort = null; | |
var currentText = null; | |
var currentHtml = null; | |
var formats = [13, 65535]; | |
var localBuffer = ""; | |
var onChangedCallbacks = []; | |
var receiverPath = ""; | |
this.start = function () { | |
if (isStarted) return; | |
var url = getWorkerUrl(3); | |
var worker = new SharedWorker(url); | |
workerPort = worker.port; | |
worker.onerror = function (error) { | |
console.log("error in clipboard plugin", error); | |
}; | |
workerPort.addEventListener("message", onWorkerMessage); | |
workerPort.start(); | |
sendMessage({ | |
"cmd": 1506 | |
}); | |
sendMessage({ | |
"cmd": 1508 | |
}); | |
sendMessage({ | |
"cmd": 317 | |
}); | |
isStarted = true; | |
}; | |
this.stop = function () { | |
if (!isStarted) return; | |
isStarted = false; | |
sendMessage({ | |
"cmd": 15, | |
"reason": null | |
}); | |
}; | |
this.setPath = function (path) { | |
receiverPath = path; | |
}; | |
this.onClipboardChanged = function (callback) { | |
if (callback) { | |
onChangedCallbacks.push(callback); | |
} | |
}; | |
this.writeText = function (text) { | |
if (localBuffer === text) return; | |
localBuffer = text; | |
saveInBuffer(text); | |
}; | |
function timeStamp() { | |
var timestamp = Date.now.bind(Date); | |
return timestamp; | |
} | |
function onWorkerMessage(event) { | |
handleRemoteMessage(event.data); | |
} | |
function handleRemoteMessage(messageData) { | |
if (messageData["source"] === 201) { | |
if (messageData["cmd"] === 303 || messageData["cmd"] === 308 || messageData["cmd"] === 313) { | |
if (messageData["cmd"] === 303) { | |
prepareLocalClipboard(messageData); | |
} else if (messageData["cmd"] === 308) { | |
pasteToRemote(messageData); | |
} else if (messageData["cmd"] === 313) { | |
pasteToLocal(messageData); | |
} | |
} | |
} | |
} | |
function getWorkerUrl(id) { | |
var receiver = receiverPath; | |
var src = receiver + "/src/"; | |
var thirdpartypath = receiver + "/ThirdPartyLibrary/"; | |
var base = "./HDXLauncher.js?filepath=" + src + "&thirdpartypath=" + thirdpartypath; | |
var path = base + "&tid=" + id; | |
return path; | |
} | |
function saveInBuffer(data) { | |
var text = data; | |
var html = ""; | |
if (text != currentData["text/plain"] || html != currentData["text/html"]) { | |
console.log("New update from local OS clipboard"); | |
currentData["text/plain"] = text; | |
currentData["text/html"] = html; | |
localTimestamp = timestamp(); | |
saveInMessageBuffer(); | |
} else if (localTimestamp < serverTimestamp) { | |
console.log("We have a new data from server but copy did not finish yet!"); | |
} | |
} | |
function saveInMessageBuffer() { | |
currentMessageData["currentDataArray"] = []; | |
currentMessageData["formatArray"] = []; | |
currentMessageData["formatname"] = []; | |
currentMessageData["timestamp"] = timestamp(); | |
currentMessageData["len"] = 0; | |
for (var i = 0; i < formats.length; i++) { | |
if (formats[i] === 13) { | |
console.trace("Adding Text Data"); | |
currentMessageData["formatname"][currentMessageData["len"]] = ""; | |
currentMessageData["formatArray"][currentMessageData["len"]] = formats[i]; | |
currentMessageData["currentDataArray"][currentMessageData["len"]] = clipboardDataParser.parse(endOfLineFormatter.localToRemote(currentData["text/plain"]), -1, 13); | |
currentMessageData["len"] += 1; | |
} | |
} | |
currentMessageData["pendingFormats"] = 0; | |
notifyRemoteAboutNewData(); | |
} | |
function notifyRemoteAboutNewData() { | |
var messageData = {}; | |
messageData["cmd"] = 302; | |
messageData["formatarr"] = currentMessageData["formatArray"]; | |
messageData["timestamp"] = currentMessageData["timestamp"]; | |
messageData["len"] = currentMessageData["len"]; | |
messageData["formatname"] = currentMessageData["formatname"]; | |
sendMessage(messageData); | |
} | |
function sendMessage(messageData) { | |
messageData["source"] = 203; | |
messageData["destination"] = 201; | |
workerPort.postMessage(messageData); | |
} | |
function pasteToLocal(messageData) { | |
if (messageData["timestamp"] === currentMessageData["timestamp"]) { | |
var index = getFormatIndex(messageData["format"], messageData["formatname"]); | |
if (index >= 0) { | |
currentMessageData["currentDataArray"][index] = messageData["data"]; | |
if (messageData["format"] === 65535 && messageData["formatname"] === "HTML Format ") { | |
console.log("received HTML Format data"); | |
currentHtml = clipboardDataParser.parse(messageData["data"], -1, "HTML Format "); | |
currentMessageData["pendingFormats"]--; | |
textToLocalClipboard(currentMessageData["timestamp"]); | |
} else if (messageData["format"] === 13) { | |
console.log("received text data"); | |
currentText = endOfLineFormatter.remoteToLocal(clipboardDataParser.parse(messageData["data"], 13, -1)); | |
currentMessageData["pendingFormats"]--; | |
textToLocalClipboard(currentMessageData["timestamp"], currentText); | |
} | |
} | |
} | |
} | |
function pasteToRemote(messageData) { | |
if (messageData["timestamp"] === currentMessageData["timestamp"]) { | |
var index = getFormatIndex(messageData["format"], messageData["formatname"]); | |
if (index >= 0) { | |
if (currentMessageData["currentDataArray"][index]) { | |
var dataToRemote = {}; | |
dataToRemote["cmd"] = 312; | |
dataToRemote["data"] = currentMessageData["currentDataArray"][index]; | |
dataToRemote["format"] = messageData["format"]; | |
dataToRemote["formatname"] = messageData["formatname"]; | |
dataToRemote["failure"] = false; | |
dataToRemote["timestamp"] = currentMessageData["timestamp"]; | |
sendMessage(data); | |
} | |
} | |
} | |
} | |
function prepareLocalClipboard(messageData) { | |
if (messageData["timestamp"] > currentMessageData["timestamp"]) { | |
currentMessageData["formatArray"] = messageData["formatarr"]; | |
currentMessageData["len"] = messageData["len"]; | |
currentMessageData["timestamp"] = messageData["timestamp"]; | |
currentMessageData["currentDataArray"] = new Array(currentMessageData["len"]); | |
currentMessageData["formatname"] = messageData["formatname"]; | |
clearClipboard(); | |
} | |
} | |
function clearClipboard() { | |
currentMessageData["pendingFormats"] = 0; | |
var formatIndex = -1; | |
for (var i = 0; i < formats.length; i++) { | |
var curFormatIndex = getFormatIndex(formats[i]); | |
if (curFormatIndex >= 0) { | |
var messageData = {}; | |
currentMessageData["pendingFormats"]++; | |
formatIndex = curFormatIndex; | |
messageData["cmd"] = 307; | |
messageData["format"] = currentMessageData["formatArray"][curFormatIndex]; | |
messageData["formatname"] = currentMessageData["formatname"][curFormatIndex]; | |
messageData["timestamp"] = currentMessageData["timestamp"]; | |
sendMessage(messageData); | |
} | |
} | |
if (currentMessageData["pendingFormats"] == 0) { | |
textToLocalClipboard(currentMessageData["timestamp"],""); | |
} else if (currentMessageData["pendingFormats"] == 1 && currentMessageData["formatArray"][formatIndex] == 13) { | |
currentHtml = ""; | |
} else if (currentMessageData["pendingFormats"] == 1 && currentMessageData["formatname"][formatIndex] == "HTML Format ") { | |
currentText = ""; | |
} | |
} | |
function textToLocalClipboard(timestamp, data) { | |
if (currentMessageData["pendingFormats"] == 0) { | |
serverTimestamp = timestamp; | |
setTimeout(function () { | |
for (var index in onChangedCallbacks) { | |
onChangedCallbacks[index](data); | |
} | |
}, 50); | |
} | |
} | |
function getFormatIndex(format) { | |
if (format == 65535) { | |
return currentMessageData["formatname"].indexOf("HTML Format "); | |
} else { | |
return currentMessageData["formatArray"].indexOf(format); | |
} | |
} | |
} | |
window.citrixClipboard = new CitrixClipboard(new ClipboardDataParser(), new EndOfLineFormatter()); | |
})(window); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment