Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save flamencist/58b74e57a3d3b3bbf95aaeb3ac008d8a to your computer and use it in GitHub Desktop.
Save flamencist/58b74e57a3d3b3bbf95aaeb3ac008d8a to your computer and use it in GitHub Desktop.
implemented citrix receiver
(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