New MeshMessenger and fixed server crash on some file copy.

Ylian Saint-Hilaire committed Oct 30, 2019 at 14:30 UTC dbe52a9780e7f510d2b1908f9fd6fabd955c4d6d
12 files changed +112 -62
meshuser.js
+23 -13
@@ -120,19 +120,29 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
120 } else return null;
121 var rootfolder = meshpath[0], rootfoldersplit = rootfolder.split('/'), domainx = 'domain';
122 if (rootfoldersplit[1].length > 0) domainx = 'domain-' + rootfoldersplit[1];
123 - var path = parent.path.join(parent.filespath, domainx, rootfoldersplit[0] + "-" + rootfoldersplit[2]);
123 + var path = parent.path.join(parent.filespath, domainx, rootfoldersplit[0] + '-' + rootfoldersplit[2]);
124 for (var i = 1; i < meshpath.length; i++) { if (common.IsFilenameValid(meshpath[i]) == false) { path = null; break; } path += ("/" + meshpath[i]); }
125 return path;
126 }
127
128 - // TODO: Replace this with something better?
128 + // Copy a file using the best technique available
129 function copyFile(src, dest, func, tag) {
130 - var ss = fs.createReadStream(src), ds = fs.createWriteStream(dest);
131 - ss.pipe(ds);
132 - ds.ss = ss;
133 - if (arguments.length == 3 && typeof arguments[2] === 'function') { ds.on('close', arguments[2]); }
134 - else if (arguments.length == 4 && typeof arguments[3] === 'function') { ds.on('close', arguments[3]); }
135 - ds.on('close', function () { func(tag); });
130 + if (fs.copyFile) {
131 + // NodeJS v8.5 and higher
132 + fs.copyFile(src, dest, function (err) { func(tag); })
133 + } else {
134 + // Older NodeJS
135 + try {
136 + var ss = fs.createReadStream(src), ds = fs.createWriteStream(dest);
137 + ss.on('error', function () { func(tag); });
138 + ds.on('error', function () { func(tag); });
139 + ss.pipe(ds);
140 + ds.ss = ss;
141 + if (arguments.length == 3 && typeof arguments[2] === 'function') { ds.on('close', arguments[2]); }
142 + else if (arguments.length == 4 && typeof arguments[3] === 'function') { ds.on('close', arguments[3]); }
143 + ds.on('close', function () { func(tag); });
144 + } catch (ex) { }
145 + }
146 }
147
148 // Route a command to a target node
@@ -607,9 +617,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
617
618 if ((command.fileop == 'createfolder') && (common.IsFilenameValid(command.newfolder) == true)) {
619 // Create a new folder
610 - try { fs.mkdirSync(path + "/" + command.newfolder); } catch (e) {
611 - try { fs.mkdirSync(path); } catch (e) { }
612 - try { fs.mkdirSync(path + "/" + command.newfolder); } catch (e) { }
620 + try { fs.mkdirSync(path + '/' + command.newfolder); } catch (ex) {
621 + try { fs.mkdirSync(path); } catch (ex) { }
622 + try { fs.mkdirSync(path + '/' + command.newfolder); } catch (ex) { }
623 }
624 }
625 else if (command.fileop == 'delete') {
@@ -619,9 +629,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
629 if (common.IsFilenameValid(command.delfiles[i]) == true) {
630 var fullpath = parent.path.join(path, command.delfiles[i]);
631 if (command.rec == true) {
622 - deleteFolderRecursive(fullpath); // TODO, make this an async function
632 + try { deleteFolderRecursive(fullpath); } catch (ex) { } // TODO, make this an async function
633 } else {
624 - try { fs.rmdirSync(fullpath); } catch (e) { try { fs.unlinkSync(fullpath); } catch (e) { } }
634 + try { fs.rmdirSync(fullpath); } catch (ex) { try { fs.unlinkSync(fullpath); } catch (xe) { } }
635 }
636 }
637 }
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.4.3-q",
3 + "version": "0.4.3-r",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
public/styles/messenger.css
+1 -1
@@ -3,10 +3,10 @@
3 border: none;
4 margin: 2px;
5 margin-top: 3px;
6 - float: right;
6 border-radius: 3px;
7 height: 32px;
8 width: 32px;
9 + float: right;
10 }
11
12 .topButton:hover {
views/default-min.handlebars
+15 -6
@@ -3524,7 +3524,7 @@
3524 if (xxdialogMode) return;
3525 var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
3526 if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
3527 - window.open(url, 'meshmessenger:' + currentNode._id);
3527 + window.open(url, 'meshmessenger:' + currentNode._id, 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=400,height=560');
3528 meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
3529 }
3530
@@ -6740,12 +6740,12 @@
6740 var h = '';
6741 if (f.t < 3 || f.t == 4) {
6742 var right = (f.t == 1 || f.t == 4)?p5getQuotabar(f):'', title = '';
6743 - h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + name + '\'>&nbsp;<span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
6743 + h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + name + '">&nbsp;<span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
6744 } else {
6745 var link = shortname, publiclink = '';
6746 - if (publicfolder) { publiclink = ' (<a style=cursor:pointer title=\"Display public link\" onclick=\'return p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>' + "Link" + '</a>)'; }
6747 - if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" download href=\"downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '\">' + shortname + '</a>' + publiclink; }
6748 - h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'>&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
6746 + if (publicfolder) { publiclink = ' (<a style=cursor:pointer title="Display public link" onclick=\'return p5showPublicLink("' + publicPath + '/' + f.nx + '")\'>' + "Link" + '</a>)'; }
6747 + if (f.s > 0) { link = '<a rel="noreferrer noopener" target="_blank" download href="downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '">' + shortname + '</a>' + publiclink; }
6748 + h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + f.nx + '">&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
6749 }
6750
6751 if (f.t < 3) { html1 += h; } else { html2 += h; }
@@ -6883,7 +6883,16 @@
6883 */
6884
6885 var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
6886 - function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
6886 + function p5copyFile(cut) {
6887 + var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation);
6888 + for (var i = 0; i < checkboxes.length; i++) {
6889 + if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) {
6890 + console.log('yy', checkboxes[i].value);
6891 + p5clipboard.push(checkboxes[i].value);
6892 + }
6893 + }
6894 + p5updateClipview();
6895 + }
6896 function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Confim {0} of {1} entrie{2} to this location?", (p5clipboardCut == 0?'copy':'move'), p5clipboard.length, ((p5clipboard.length > 1)?'s':'')) } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
6897 function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0?'copy':'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
6898 function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Holding {0} entrie{1} for {2}", p5clipboard.length, ((p5clipboard.length > 1)?'s':''), (p5clipboardCut == 0?"copy":"move")) + ', <a href=# onclick="return p5clearClip()" style=cursor:pointer>' + "Clear" + '</a>.' } QH('p5bottomstatus', x); p5setActions(); }
views/default.handlebars
+15 -6
@@ -4506,7 +4506,7 @@
4506 if (xxdialogMode) return;
4507 var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
4508 if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
4509 - window.open(url, 'meshmessenger:' + currentNode._id);
4509 + window.open(url, 'meshmessenger:' + currentNode._id, 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=400,height=560');
4510 meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
4511 }
4512
@@ -7722,12 +7722,12 @@
7722 var h = '';
7723 if (f.t < 3 || f.t == 4) {
7724 var right = (f.t == 1 || f.t == 4)?p5getQuotabar(f):'', title = '';
7725 - h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + name + '\'>&nbsp;<span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
7725 + h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + name + '">&nbsp;<span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
7726 } else {
7727 var link = shortname, publiclink = '';
7728 - if (publicfolder) { publiclink = ' (<a style=cursor:pointer title=\"Display public link\" onclick=\'return p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>' + "Link" + '</a>)'; }
7729 - if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" download href=\"downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '\">' + shortname + '</a>' + publiclink; }
7730 - h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'>&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
7728 + if (publicfolder) { publiclink = ' (<a style=cursor:pointer title="Display public link" onclick=\'return p5showPublicLink("' + publicPath + '/' + f.nx + '")\'>' + "Link" + '</a>)'; }
7729 + if (f.s > 0) { link = '<a rel="noreferrer noopener" target="_blank" download href="downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '">' + shortname + '</a>' + publiclink; }
7730 + h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + f.nx + '">&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
7731 }
7732
7733 if (f.t < 3) { html1 += h; } else { html2 += h; }
@@ -7865,7 +7865,16 @@
7865 */
7866
7867 var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
7868 - function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
7868 + function p5copyFile(cut) {
7869 + var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation);
7870 + for (var i = 0; i < checkboxes.length; i++) {
7871 + if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) {
7872 + console.log('yy', checkboxes[i].value);
7873 + p5clipboard.push(checkboxes[i].value);
7874 + }
7875 + }
7876 + p5updateClipview();
7877 + }
7878 function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Confim {0} of {1} entrie{2} to this location?", (p5clipboardCut == 0?'copy':'move'), p5clipboard.length, ((p5clipboard.length > 1)?'s':'')) } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
7879 function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0?'copy':'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
7880 function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Holding {0} entrie{1} for {2}", p5clipboard.length, ((p5clipboard.length > 1)?'s':''), (p5clipboardCut == 0?"copy":"move")) + ', <a href=# onclick="return p5clearClip()" style=cursor:pointer>' + "Clear" + '</a>.' } QH('p5bottomstatus', x); p5setActions(); }
views/messenger-min.handlebars
+1 -1
@@ -1 +1 @@
1 -<!doctypehtml><html style=height:100%><title>MeshMessenger</title><meta http-equiv=X-UA-Compatible content="IE=edge"><meta content="text/html;charset=utf-8"http-equiv=Content-Type><meta name=format-detection content="telephone=no"><link type=text/css href=styles/style.css media=screen rel=stylesheet title=CSS><link type=text/css href=styles/messenger.css media=screen rel=stylesheet title=CSS><script src=scripts/common-0.0.1.js></script><script src=scripts/filesaver.js></script><body style=font-family:Arial,Helvetica,sans-serif><div id=xtop style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray"><div id=notifyButton class="icon13 topButton"style=margin-right:4px;display:none title="Enable browser notification"onclick=enableNotificationsButtonClick()></div><div id=fileButton class="icon4 topButton"title="Share a file"style=display:none onclick=fileButtonClick()></div><div id=camButton class="icon2 topButton"title="Activate camera & microphone"style=display:none onclick=camButtonClick()></div><div id=micButton class="icon6 topButton"title="Activate microphone"style=display:none onclick=micButtonClick()></div><div id=hangupButton class="icon11 topRedButton"title="Hang up"style=display:none onclick=hangUpButtonClick(1)></div><div style=display:inline-block;width:2px></div><div style=padding-top:9px;padding-left:6px;font-size:20px;display:inline-block><b>MeshMessenger<span id=xtitle></span></b></div></div><div id=xmiddle style=position:absolute;left:0;right:0;top:38px;bottom:30px><div style=position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll><div id=xmsg style=position:absolute;left:0;right:0;bottom:0;padding:5px></div></div></div><div id=xbottom style=position:absolute;left:0;right:0;bottom:0;height:30px;background-color:#036><div style=position:absolute;left:5px;right:215px;bottom:4px;top:4px;background-color:#f0f8ff><input id=xouttext style="width:calc(100% - 5px)"onfocus=onUserInputFocus(1) onblur=onUserInputFocus(0)></div><input type=button id=sendButton value=Send style=position:absolute;right:110px;width:100px;top:4px onclick=xsend(event)> <input type=button id=clearButton value=Clear style=position:absolute;right:5px;width:100px;top:4px onclick=displayClear()></div><div id=remoteVideo style="position:absolute;right:24px;top:45px;width:320px;height:calc(240px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none"><div style=position:absolute;right:0;left:0;top:2.5px;text-align:center>Remote</div><video id=remoteVideoCanvas autoplay style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:#000"></video></div><div id=localVideo style="position:absolute;right:24px;top:320px;width:160px;height:calc(120px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none"><div style=position:absolute;right:0;left:0;top:2.5px;text-align:center>Local</div><video id=localVideoCanvas autoplay muted style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:#000"></video></div><input id=uploadFileInput type=file multiple style=display:none><script onunload=onUnLoad()>var userInputFocus=0,args=parseUriArgs(),socket=null,state=0,random=Math.random(),webrtcSessions={},webchannel=null,localStream=null,remoteStream=null,multiWebRtc=!0,userMediaSupport=0,notification=null;getUserMediaSupport(function(e){userMediaSupport=e});var webrtcconfiguration="{{{webrtconfig}}}";if(""==webrtcconfiguration)webrtcconfiguration=null;else try{webrtcconfiguration=JSON.parse(decodeURIComponent(webrtcconfiguration))}catch(e){console.log('Invalid WebRTC config: "'+webrtcconfiguration+'".'),webrtcconfiguration=null}var fileUploads=[],fileDownloads={},currentFileUpload=null,currentFileDownload=null;function onUserInputFocus(e){userInputFocus=e}function displayClear(){QH("xmsg",""),cancelAllFileTransfers(),fileUploads=[],fileDownloads={}}function getUserMediaSupport(i){try{navigator.mediaDevices.enumerateDevices().then(function(e){try{var t=0,n=0;e.forEach(function(e){"audioinput"===e.kind&&(t=1),"videoinput"===e.kind&&(n=1)}),0==t&&i(0),i(t+n)}catch(e){}})}catch(e){}}function displayControl(e){QA("xmsg",'<div style="clear:both"><div style="color:gray;float:left;margin-bottom:2px">'+e+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight}function displayLocalVideo(e){QV("localVideo",e),adjustVideoWindows()}function displayRemoteVideo(e){QV("remoteVideo",e),adjustVideoWindows()}function adjustVideoWindows(){var e="none"!=QS("remoteVideo").display;QS("localVideo").top=e?"320px":"45px"}function displayRemote(e){QA("xmsg",'<div style="clear:both"><div class="remoteBubble">'+e+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,Notification&&QV("notifyButton","granted"!=Notification.permission),Notification&&"granted"==Notification.permission&&(null!=notification&&(notification.close(),notification=null),notification=args.title?new Notification("MeshMessenger - "+args.title,{body:e}):new Notification("MeshMessenger",{body:e}))}function xsend(e){null!=notification&&(notification.close(),notification=null),Notification&&QV("notifyButton","granted"!=Notification.permission);var t=Q("xouttext").value;0<t.length&&(Q("xouttext").value="",QA("xmsg",'<div style="clear:both"><div class="localBubble">'+t+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,send({action:"chat",msg:t}))}function haltEvent(e){return e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),!1}function parseUriArgs(){var e,t={},n=window.document.location.href.split(/[\?&|\=]/);for(i in n.splice(0,1),n)switch(i%2){case 0:e=decodeURIComponent(n[i]);break;case 1:t[e]=decodeURIComponent(n[i]);var i=parseInt(t[e]);i==t[e]&&(t[e]=i)}return t}function updateControls(){QE("sendButton",2==state),QE("clearButton",2==state),QE("xouttext",2==state),QV("fileButton",2==state),QV("camButton",webchannel&&webchannel.ok&&!localStream&&2==userMediaSupport),QV("micButton",webchannel&&webchannel.ok&&!localStream&&0<userMediaSupport),QV("hangupButton",webchannel&&webchannel.ok&&localStream)}function startWebRTC(t,e){if(null!=webrtcSessions[0]&&0==multiWebRtc)return webrtcSessions[0];var n=null;return"undefined"!=typeof RTCPeerConnection?n=new RTCPeerConnection(webrtcconfiguration):"undefined"!=typeof webkitRTCPeerConnection&&(n=new webkitRTCPeerConnection(webrtcconfiguration)),null==n?null:(n.id=t,n.onicecandidate=function(e){try{null!=e.candidate&&sendws({action:"webRtcIce",ice:e.candidate,id:this.id})}catch(e){}},n.oniceconnectionstatechange=function(){n&&"failed"==n.iceConnectionState&&(n.close(),webrtcSessions[n.id]&&delete webrtcSessions[n.id])},n.ondatachannel=function(e){(webchannel=e.channel).onmessage=function(e){processMessage(e.data,2)},webchannel.onopen=function(){webchannel.ok=!0,updateControls(),sendws({action:"rtcSwitch",v:0})},webchannel.onclose=function(e){webchannel&&webchannel.ok?disconnect():hangUpButtonClick(0)}},n.onnegotiationneeded=function(e){null==n.holdTimer&&(n.holdTimer=setTimeout(function(){n.holdTimer=null,n.createOffer(function(e){n.setLocalDescription(e,function(){sendws({action:"webRtcSdp",sdp:e,id:t})},function(){hangUpButtonClick(t)})},function(){hangUpButtonClick(t)})},20))},n.ontrack=function(e){var t=Q("remoteVideoCanvas");t.srcObject=remoteStream=e.streams[0],t.onloadedmetadata=function(e){t.play()},displayRemoteVideo(!0)},1==e&&((webchannel=n.createDataChannel("DataChannel",{})).onmessage=function(e){processMessage(e.data,2)},webchannel.onopen=function(){webchannel.ok=!0,updateControls(),sendws({action:"rtcSwitch",v:0})},webchannel.onclose=function(e){webchannel&&webchannel.ok?disconnect():hangUpButtonClick(0)}),webrtcSessions[t]=n)}function webRtcHandleOffer(i,e){var t=webrtcSessions[i];t&&t.setRemoteDescription(new RTCSessionDescription(e),function(){"offer"==e.type&&t.createAnswer(function(n){t.setLocalDescription(n,function(e,t){try{sendws({action:"webRtcSdp",sdp:n,id:i})}catch(e){}},function(){hangUpButtonClick(i)})},function(){hangUpButtonClick(i)})},function(){hangUpButtonClick(i)})}function performWebRtcSwitch(){webchannel&&webchannel.ok&&(sendws({action:"rtcSwitch",v:1}),webchannel.xoutBuffer=[])}function disconnect(){0<state&&displayControl("Connection closed."),1<state&&setTimeout(start,500),cancelAllFileTransfers(),hangUpButtonClick(0,!0),hangUpButtonClick(1,!0),hangUpButtonClick(2,!0),null!=socket&&(socket.close(),socket=null),updateControls(),state=0}function send(e){if(2==state)if("object"==typeof e&&(e=JSON.stringify(e)),webchannel&&webchannel.ok)null!=webchannel.xoutBuffer?webchannel.xoutBuffer.push(e):webchannel.send(e);else if(null!=socket)try{socket.send(e)}catch(e){}}function sendws(e){2==state&&("object"==typeof e&&(e=JSON.stringify(e)),null!=socket&&socket.send(e))}function webRtcIdSwitch(e){return 0==e?0:3-e}function processMessage(t,e){if("string"==typeof t){try{t=JSON.parse(t)}catch(e){return void console.log("Unable to parse",t)}switch(t.action){case"chat":displayRemote(t.msg);break;case"random":random>t.random&&startWebRTC(0,!0);break;case"webRtcSdp":webrtcSessions[webRtcIdSwitch(t.id)]||startWebRTC(webRtcIdSwitch(t.id),!1),webRtcHandleOffer(webRtcIdSwitch(t.id),t.sdp);break;case"webRtcIce":var n=webrtcSessions[webRtcIdSwitch(t.id)];if(n)try{n.addIceCandidate(new RTCIceCandidate(t.ice))}catch(e){}break;case"videoStop":hangUpButtonClick(webRtcIdSwitch(t.id),!0);break;case"rtcSwitch":switch(t.v){case 0:performWebRtcSwitch();break;case 1:sendws({action:"rtcSwitch",v:2});break;case 2:for(var i in webchannel.xoutBuffer)webchannel.send(webchannel.xoutBuffer[i]);delete webchannel.xoutBuffer;break;default:console.log("Unknown rtcSwitch value: "+t.action)}break;case"file":startFileDownload(t);break;case"fileUploadCancel":cancelFileTransfer(t.id);break;case"fileUploadStart":fileDownloads[t.id]&&((currentFileDownload=fileDownloads[t.id]).data="",changeFileInfo(t.id,2,0),continueFileDownload(t),send({action:"fileUploadAck",id:t.id}));break;case"fileUploadEnd":currentFileDownload&&currentFileDownload.id==t.id&&(changeFileInfo(t.id,3,200),currentFileDownload.done=1,currentFileDownload=null,send({action:"fileUploadAck",id:t.id})),currentFileDownload=null;break;case"fileUploadAck":continueFileUpload();break;case"fileData":currentFileDownload&&currentFileDownload.id==t.id&&(currentFileDownload.data+=t.data,changeFileInfo(t.id,2,200*currentFileDownload.data.length/currentFileDownload.size),send({action:"fileUploadAck",id:t.id}));break;default:console.log("Unhandled object data",t)}}else console.log("Unhandled data",typeof t,t)}function fileButtonClick(){var e=Q("uploadFileInput");1!=e.getAttribute("eventset")&&(e.setAttribute("eventset","1"),e.addEventListener("change",fileSelect,!1)),e.value=null,e.click()}function fileSelect(){if(2==state){var e=Q("uploadFileInput");if(10<e.files.length)displayControl("Limit of 10 file uploads at the same time.");else for(var t=0;t<e.files.length;t++)if(0<e.files[t].size){var n=new FileReader;n.onload=function(e){this.xfile.data=e.target.result,startFileUpload(this.xfile)},n.xfile=e.files[t],n.readAsBinaryString(e.files[t])}}}function fileDrop(e){if(haltEvent(e),2==state&&null!=e.dataTransfer)if(10<e.dataTransfer.files.length)displayControl("Limit of 10 file uploads at the same time.");else for(var t=0;t<e.dataTransfer.files.length;t++)if(0<e.dataTransfer.files[t].size){var n=new FileReader;n.onload=function(e){this.xfile.data=e.target.result,startFileUpload(this.xfile)},n.xfile=e.dataTransfer.files[t],n.readAsBinaryString(e.dataTransfer.files[t])}}function startFileUpload(e){2==state&&(e.id=Math.random(),fileUploads.push(e),QA("xmsg",'<div style="clear:both"></div><div id="FILEUP-'+e.id+'" class="localBubble" style="width:240px;cursor:pointer" onclick="cancelFileTransfer(\''+e.id+'\')"><div id="FILEUP-ICON-'+e.id+'" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-'+e.id+'" style="height:16px;overflow:hidden;white-space:nowrap;" title="'+e.name+'">'+e.name+'</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-'+e.id+'" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>'),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,send({action:"file",size:e.size,id:e.id,type:e.type,name:e.name}),null==currentFileUpload&&continueFileUpload())}function startFileDownload(e){2==state&&(fileDownloads[e.id]=e,QA("xmsg",'<div style="clear:both"></div><div id="FILEUP-'+e.id+'" class="remoteBubble" style="width:240px;cursor:pointer" onclick="saveFileTransfer(\''+e.id+'\')"><div id="FILEUP-ICON-'+e.id+'" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-'+e.id+'" style="height:16px;overflow:hidden;white-space:nowrap;" title="'+e.name+'">'+e.name+'</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-'+e.id+'" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>'),Q("xmsg").scrollTop=Q("xmsg").scrollHeight)}function changeFileInfo(e,t,n,i){t&&(Q("FILEUP-ICON-"+e).classList.remove("fileicon"),Q("FILEUP-ICON-"+e).classList.remove("fileiconx"),Q("FILEUP-ICON-"+e).classList.remove("fileicontransfer"),Q("FILEUP-ICON-"+e).classList.remove("fileicondone"),Q("FILEUP-ICON-"+e).classList.add(["fileicon","fileiconx","fileicontransfer","fileicondone"][t])),n&&(QS("FILEUP-PROGRESS-"+e).width=n+"px"),i&&(QS("FILEUP-PROGRESS-"+e)["background-color"]=i)}function data2blob(e){for(var t=new Array(e.length),n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return new Blob([new Uint8Array(t)])}function saveFileTransfer(e){var t=fileDownloads[e];t&&1==t.done&&saveAs(data2blob(t.data),t.name)}function cancelFileTransfer(e){null!=currentFileUpload&&currentFileUpload.id==e&&(currentFileUpload=null),null!=currentFileDownload&&currentFileDownload.id==e&&(currentFileDownload=null);var t=!1;if(fileDownloads[e]&&1!=fileDownloads[e].done)delete fileDownloads[e],t=!0;else for(var n in fileUploads)if(fileUploads[n].id==e){send({action:"fileUploadCancel",id:e}),fileUploads.splice(n,1),t=!0;break}t&&changeFileInfo(e,1,200,"gray")}function cancelAllFileTransfers(){for(var e in fileDownloads)cancelFileTransfer(fileDownloads[e].id);for(var e in fileUploads)cancelFileTransfer(fileUploads[e].id)}function continueFileUpload(){if(null==currentFileUpload){if(0==fileUploads.length)return;(currentFileUpload=fileUploads[0]).ptr=0,send({action:"fileUploadStart",size:currentFileUpload.size,id:currentFileUpload.id,type:currentFileUpload.type,name:currentFileUpload.name})}else if(currentFileUpload.size<=currentFileUpload.ptr)send({action:"fileUploadEnd",size:currentFileUpload.size,id:currentFileUpload.id,type:currentFileUpload.type,name:currentFileUpload.name}),changeFileInfo(currentFileUpload.id,3,200),fileUploads.splice(0,1),currentFileUpload=null,continueFileUpload();else{var e=Math.min(4e3,currentFileUpload.data.length-currentFileUpload.ptr),t=currentFileUpload.data.substring(currentFileUpload.ptr,currentFileUpload.ptr+e);send({action:"fileData",id:currentFileUpload.id,data:t}),currentFileUpload.ptr+=e,changeFileInfo(currentFileUpload.id,0,200*currentFileUpload.ptr/currentFileUpload.size)}}function continueFileDownload(e){send({action:"fileUploadAck",id:e.id})}function enableNotificationsButtonClick(){return Notification&&Notification.requestPermission().then(function(e){QV("notifyButton","granted"!=e)}),!1}function camButtonClick(){null==localStream&&startLocalStream({video:!0,audio:!0})}function micButtonClick(){null==localStream&&startLocalStream({video:!1,audio:!0})}function hangUpButtonClick(e,t){var n=Q("localVideoCanvas"),i=Q("remoteVideoCanvas"),o=webrtcSessions[1==multiWebRtc?e:0];if(0==e&&null!=webchannel){try{webchannel.close()}catch(e){}webchannel=null}if(o){if(1!=multiWebRtc&&0!=e||(o.ontrack=null,o.onremovetrack=null,o.onremovestream=null,o.onnicecandidate=null,o.oniceconnectionstatechange=null,o.onsignalingstatechange=null,o.onicegatheringstatechange=null,o.onnotificationneeded=null),1==e&&localStream){var a=localStream.getTracks();for(var l in a)a[l].stop();localStream=null}if(2==e&&remoteStream){a=remoteStream.getTracks();for(var l in a)a[l].stop();remoteStream=null}1!=multiWebRtc&&0!=e||(o.close(),delete webrtcSessions[e])}1==e?(n.removeAttribute("src"),n.removeAttribute("srcObject"),null!=localStream&&(localStream=null),displayLocalVideo(!1)):2==e&&(i.removeAttribute("src"),i.removeAttribute("srcObject"),displayRemoteVideo(!1)),1!=t&&send({action:"videoStop",id:e}),updateControls()}function startLocalStream(a){var l=1==multiWebRtc?1:0;null==localStream&&(1==multiWebRtc&&null!=webrtcSessions[1]||navigator.mediaDevices.getUserMedia&&(localStream=1,updateControls(),navigator.mediaDevices.getUserMedia(a).then(function(e){var t=(localStream=e).getTracks(),n=startWebRTC(l);if(1==a.video){var i=Q("localVideoCanvas");i.srcObject=e,i.onloadedmetadata=function(e){i.play()},displayLocalVideo(!0)}for(var o in t)n.addTrack(t[o],localStream)},function(e){displayControl(e.message+"."),hangUpButtonClick(1)})))}function start(){if(updateControls(),"string"==typeof args.id&&0<args.id.length){var e=window.location.protocol.replace("http","ws")+"//"+window.location.host+window.location.pathname.substring(0,window.location.pathname.lastIndexOf("/"))+"/meshrelay.ashx?id="+args.id;null!=args.auth&&""!=args.auth&&(e+="&auth="+args.auth),(socket=new WebSocket(e)).onopen=function(){state=1,displayControl("Waiting for other user...")},socket.onerror=function(e){},socket.onclose=function(){disconnect()},socket.onmessage=function(e){if(state<2&&"string"==typeof e.data&&("c"==e.data||"cr"==e.data))return hangUpButtonClick(0,!0),hangUpButtonClick(1,!0),hangUpButtonClick(2,!0),displayControl("Connected."),state=2,updateControls(),void sendws({action:"random",random:random});2==state&&processMessage(e.data,1)}}else displayControl("Error: No connection key specified.")}function onUnLoad(){for(var e=0;e<3;e++)webrtcSessions[e]&&(webrtcSessions[e].close(),delete webrtcSessions[e]);if(null!=webchannel){try{webchannel.close()}catch(e){}webchannel=null}if(null!=socket){try{socket.close()}catch(e){}socket=null}}args.title&&(QH("xtitle"," - "+args.title),document.title=document.title+" - "+args.title),Notification&&QV("notifyButton","granted"!=Notification.permission),document.addEventListener("dragover",haltEvent,!1),document.addEventListener("dragleave",haltEvent,!1),document.addEventListener("drop",fileDrop,!1),document.onclick=function(e){Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null)},document.onkeyup=function(e){if(Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null),2==state&&8==e.keyCode&&0==userInputFocus){var t=Q("xouttext").value;0<t.length&&(Q("xouttext").value=t.substring(0,t.length-1))}if(0==userInputFocus)return haltEvent(e),!1},document.onkeypress=function(e){if(Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null),2==state&&(13==e.keyCode?xsend(e):0==userInputFocus&&1==e.key.length&&(Q("xouttext").value=Q("xouttext").value+e.key)),0==userInputFocus)return haltEvent(e),!1},FileReader.prototype.readAsBinaryString||(FileReader.prototype.readAsBinaryString=function(e){var i="",o=this,a=new FileReader;a.onload=function(e){for(var t=new Uint8Array(a.result),n=0;n<t.byteLength;n++)i+=String.fromCharCode(t[n]);o.onload({target:{result:i}})},a.readAsArrayBuffer(e)}),start()</script>
\ No newline at end of file
1 +<!doctypehtml><html style=height:100%><title>MeshMessenger</title><meta http-equiv=X-UA-Compatible content="IE=edge"><meta content="text/html;charset=utf-8"http-equiv=Content-Type><meta name=format-detection content="telephone=no"><link type=text/css href=styles/style.css media=screen rel=stylesheet title=CSS><link type=text/css href=styles/messenger.css media=screen rel=stylesheet title=CSS><script src=scripts/common-0.0.1.js></script><script src=scripts/filesaver.js></script><body style=font-family:Arial,Helvetica,sans-serif><div id=xtop style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray"><div style=position:absolute;background-color:#036;right:0;height:38px><div id=notifyButton class="icon13 topButton"style=margin-right:4px;display:none title="Enable browser notification"onclick=enableNotificationsButtonClick()></div><div id=fileButton class="icon4 topButton"title="Share a file"style=display:none onclick=fileButtonClick()></div><div id=camButton class="icon2 topButton"title="Activate camera & microphone"style=display:none onclick=camButtonClick()></div><div id=micButton class="icon6 topButton"title="Activate microphone"style=display:none onclick=micButtonClick()></div><div id=hangupButton class="icon11 topRedButton"title="Hang up"style=display:none onclick=hangUpButtonClick(1)></div></div><div style=padding-top:9px;padding-left:6px;font-size:20px;display:inline-block><b><span id=xtitle>MeshMessenger</span></b></div></div><div id=xmiddle style=position:absolute;left:0;right:0;top:38px;bottom:30px><div style=position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll><div id=xmsg style=position:absolute;left:0;right:0;bottom:0;padding:5px></div></div></div><div id=xbottom style=position:absolute;left:0;right:0;bottom:0;height:30px;background-color:#036><div style=position:absolute;left:5px;right:215px;bottom:4px;top:4px;background-color:#f0f8ff><input id=xouttext style="width:calc(100% - 5px)"onfocus=onUserInputFocus(1) onblur=onUserInputFocus(0)></div><input type=button id=sendButton value=Send style=position:absolute;right:110px;width:100px;top:4px onclick=xsend(event)> <input type=button id=clearButton value=Clear style=position:absolute;right:5px;width:100px;top:4px onclick=displayClear()></div><div id=remoteVideo style="position:absolute;right:24px;top:45px;width:320px;height:calc(240px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none"><div style=position:absolute;right:0;left:0;top:2.5px;text-align:center>Remote</div><video id=remoteVideoCanvas autoplay style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:#000"></video></div><div id=localVideo style="position:absolute;right:24px;top:320px;width:160px;height:calc(120px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none"><div style=position:absolute;right:0;left:0;top:2.5px;text-align:center>Local</div><video id=localVideoCanvas autoplay muted style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:#000"></video></div><input id=uploadFileInput type=file multiple style=display:none><script onunload=onUnLoad()>var userInputFocus=0,args=parseUriArgs(),socket=null,state=0,random=Math.random(),webrtcSessions={},webchannel=null,localStream=null,remoteStream=null,multiWebRtc=!0,userMediaSupport=0,notification=null;getUserMediaSupport(function(e){userMediaSupport=e});var webrtcconfiguration="{{{webrtconfig}}}";if(""==webrtcconfiguration)webrtcconfiguration=null;else try{webrtcconfiguration=JSON.parse(decodeURIComponent(webrtcconfiguration))}catch(e){console.log('Invalid WebRTC config: "'+webrtcconfiguration+'".'),webrtcconfiguration=null}var fileUploads=[],fileDownloads={},currentFileUpload=null,currentFileDownload=null;function onUserInputFocus(e){userInputFocus=e}function displayClear(){QH("xmsg",""),cancelAllFileTransfers(),fileUploads=[],fileDownloads={}}function getUserMediaSupport(i){try{navigator.mediaDevices.enumerateDevices().then(function(e){try{var t=0,n=0;e.forEach(function(e){"audioinput"===e.kind&&(t=1),"videoinput"===e.kind&&(n=1)}),0==t&&i(0),i(t+n)}catch(e){}})}catch(e){}}function displayControl(e){QA("xmsg",'<div style="clear:both"><div style="color:gray;float:left;margin-bottom:2px">'+e+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight}function displayLocalVideo(e){QV("localVideo",e),adjustVideoWindows()}function displayRemoteVideo(e){QV("remoteVideo",e),adjustVideoWindows()}function adjustVideoWindows(){var e="none"!=QS("remoteVideo").display;QS("localVideo").top=e?"320px":"45px"}function displayRemote(e){QA("xmsg",'<div style="clear:both"><div class="remoteBubble">'+e+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,Notification&&QV("notifyButton","granted"!=Notification.permission),Notification&&"granted"==Notification.permission&&(null!=notification&&(notification.close(),notification=null),notification=args.title?new Notification("MeshMessenger - "+args.title,{body:e}):new Notification("MeshMessenger",{body:e}))}function xsend(e){null!=notification&&(notification.close(),notification=null),Notification&&QV("notifyButton","granted"!=Notification.permission);var t=Q("xouttext").value;0<t.length&&(Q("xouttext").value="",QA("xmsg",'<div style="clear:both"><div class="localBubble">'+t+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,send({action:"chat",msg:t}))}function haltEvent(e){return e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),!1}function parseUriArgs(){var e,t={},n=window.document.location.href.split(/[\?&|\=]/);for(i in n.splice(0,1),n)switch(i%2){case 0:e=decodeURIComponent(n[i]);break;case 1:t[e]=decodeURIComponent(n[i]);var i=parseInt(t[e]);i==t[e]&&(t[e]=i)}return t}function updateControls(){QE("sendButton",2==state),QE("clearButton",2==state),QE("xouttext",2==state),QV("fileButton",2==state),QV("camButton",webchannel&&webchannel.ok&&!localStream&&2==userMediaSupport),QV("micButton",webchannel&&webchannel.ok&&!localStream&&0<userMediaSupport),QV("hangupButton",webchannel&&webchannel.ok&&localStream)}function startWebRTC(t,e){if(null!=webrtcSessions[0]&&0==multiWebRtc)return webrtcSessions[0];var n=null;return"undefined"!=typeof RTCPeerConnection?n=new RTCPeerConnection(webrtcconfiguration):"undefined"!=typeof webkitRTCPeerConnection&&(n=new webkitRTCPeerConnection(webrtcconfiguration)),null==n?null:(n.id=t,n.onicecandidate=function(e){try{null!=e.candidate&&sendws({action:"webRtcIce",ice:e.candidate,id:this.id})}catch(e){}},n.oniceconnectionstatechange=function(){n&&"failed"==n.iceConnectionState&&(n.close(),webrtcSessions[n.id]&&delete webrtcSessions[n.id])},n.ondatachannel=function(e){(webchannel=e.channel).onmessage=function(e){processMessage(e.data,2)},webchannel.onopen=function(){webchannel.ok=!0,updateControls(),sendws({action:"rtcSwitch",v:0})},webchannel.onclose=function(e){webchannel&&webchannel.ok?disconnect():hangUpButtonClick(0)}},n.onnegotiationneeded=function(e){null==n.holdTimer&&(n.holdTimer=setTimeout(function(){n.holdTimer=null,n.createOffer(function(e){n.setLocalDescription(e,function(){sendws({action:"webRtcSdp",sdp:e,id:t})},function(){hangUpButtonClick(t)})},function(){hangUpButtonClick(t)})},20))},n.ontrack=function(e){var t=Q("remoteVideoCanvas");t.srcObject=remoteStream=e.streams[0],t.onloadedmetadata=function(e){t.play()},displayRemoteVideo(!0)},1==e&&((webchannel=n.createDataChannel("DataChannel",{})).onmessage=function(e){processMessage(e.data,2)},webchannel.onopen=function(){webchannel.ok=!0,updateControls(),sendws({action:"rtcSwitch",v:0})},webchannel.onclose=function(e){webchannel&&webchannel.ok?disconnect():hangUpButtonClick(0)}),webrtcSessions[t]=n)}function webRtcHandleOffer(i,e){var t=webrtcSessions[i];t&&t.setRemoteDescription(new RTCSessionDescription(e),function(){"offer"==e.type&&t.createAnswer(function(n){t.setLocalDescription(n,function(e,t){try{sendws({action:"webRtcSdp",sdp:n,id:i})}catch(e){}},function(){hangUpButtonClick(i)})},function(){hangUpButtonClick(i)})},function(){hangUpButtonClick(i)})}function performWebRtcSwitch(){webchannel&&webchannel.ok&&(sendws({action:"rtcSwitch",v:1}),webchannel.xoutBuffer=[])}function disconnect(){0<state&&displayControl("Connection closed."),1<state&&setTimeout(start,500),cancelAllFileTransfers(),hangUpButtonClick(0,!0),hangUpButtonClick(1,!0),hangUpButtonClick(2,!0),null!=socket&&(socket.close(),socket=null),updateControls(),state=0}function send(e){if(2==state)if("object"==typeof e&&(e=JSON.stringify(e)),webchannel&&webchannel.ok)null!=webchannel.xoutBuffer?webchannel.xoutBuffer.push(e):webchannel.send(e);else if(null!=socket)try{socket.send(e)}catch(e){}}function sendws(e){2==state&&("object"==typeof e&&(e=JSON.stringify(e)),null!=socket&&socket.send(e))}function webRtcIdSwitch(e){return 0==e?0:3-e}function processMessage(t,e){if("string"==typeof t){try{t=JSON.parse(t)}catch(e){return void console.log("Unable to parse",t)}switch(t.action){case"chat":displayRemote(t.msg);break;case"random":random>t.random&&startWebRTC(0,!0);break;case"webRtcSdp":webrtcSessions[webRtcIdSwitch(t.id)]||startWebRTC(webRtcIdSwitch(t.id),!1),webRtcHandleOffer(webRtcIdSwitch(t.id),t.sdp);break;case"webRtcIce":var n=webrtcSessions[webRtcIdSwitch(t.id)];if(n)try{n.addIceCandidate(new RTCIceCandidate(t.ice))}catch(e){}break;case"videoStop":hangUpButtonClick(webRtcIdSwitch(t.id),!0);break;case"rtcSwitch":switch(t.v){case 0:performWebRtcSwitch();break;case 1:sendws({action:"rtcSwitch",v:2});break;case 2:for(var i in webchannel.xoutBuffer)webchannel.send(webchannel.xoutBuffer[i]);delete webchannel.xoutBuffer;break;default:console.log("Unknown rtcSwitch value: "+t.action)}break;case"file":startFileDownload(t);break;case"fileUploadCancel":cancelFileTransfer(t.id);break;case"fileUploadStart":fileDownloads[t.id]&&((currentFileDownload=fileDownloads[t.id]).data="",changeFileInfo(t.id,2,0),continueFileDownload(t),send({action:"fileUploadAck",id:t.id}));break;case"fileUploadEnd":currentFileDownload&&currentFileDownload.id==t.id&&(changeFileInfo(t.id,3,200),currentFileDownload.done=1,currentFileDownload=null,send({action:"fileUploadAck",id:t.id})),currentFileDownload=null;break;case"fileUploadAck":continueFileUpload();break;case"fileData":currentFileDownload&&currentFileDownload.id==t.id&&(currentFileDownload.data+=t.data,changeFileInfo(t.id,2,200*currentFileDownload.data.length/currentFileDownload.size),send({action:"fileUploadAck",id:t.id}));break;default:console.log("Unhandled object data",t)}}else console.log("Unhandled data",typeof t,t)}function fileButtonClick(){var e=Q("uploadFileInput");1!=e.getAttribute("eventset")&&(e.setAttribute("eventset","1"),e.addEventListener("change",fileSelect,!1)),e.value=null,e.click()}function fileSelect(){if(2==state){var e=Q("uploadFileInput");if(10<e.files.length)displayControl("Limit of 10 file uploads at the same time.");else for(var t=0;t<e.files.length;t++)if(0<e.files[t].size){var n=new FileReader;n.onload=function(e){this.xfile.data=e.target.result,startFileUpload(this.xfile)},n.xfile=e.files[t],n.readAsBinaryString(e.files[t])}}}function fileDrop(e){if(haltEvent(e),2==state&&null!=e.dataTransfer)if(10<e.dataTransfer.files.length)displayControl("Limit of 10 file uploads at the same time.");else for(var t=0;t<e.dataTransfer.files.length;t++)if(0<e.dataTransfer.files[t].size){var n=new FileReader;n.onload=function(e){this.xfile.data=e.target.result,startFileUpload(this.xfile)},n.xfile=e.dataTransfer.files[t],n.readAsBinaryString(e.dataTransfer.files[t])}}function startFileUpload(e){2==state&&(e.id=Math.random(),fileUploads.push(e),QA("xmsg",'<div style="clear:both"></div><div id="FILEUP-'+e.id+'" class="localBubble" style="width:240px;cursor:pointer" onclick="cancelFileTransfer(\''+e.id+'\')"><div id="FILEUP-ICON-'+e.id+'" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-'+e.id+'" style="height:16px;overflow:hidden;white-space:nowrap;" title="'+e.name+'">'+e.name+'</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-'+e.id+'" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>'),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,send({action:"file",size:e.size,id:e.id,type:e.type,name:e.name}),null==currentFileUpload&&continueFileUpload())}function startFileDownload(e){2==state&&(fileDownloads[e.id]=e,QA("xmsg",'<div style="clear:both"></div><div id="FILEUP-'+e.id+'" class="remoteBubble" style="width:240px;cursor:pointer" onclick="saveFileTransfer(\''+e.id+'\')"><div id="FILEUP-ICON-'+e.id+'" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-'+e.id+'" style="height:16px;overflow:hidden;white-space:nowrap;" title="'+e.name+'">'+e.name+'</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-'+e.id+'" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>'),Q("xmsg").scrollTop=Q("xmsg").scrollHeight)}function changeFileInfo(e,t,n,i){t&&(Q("FILEUP-ICON-"+e).classList.remove("fileicon"),Q("FILEUP-ICON-"+e).classList.remove("fileiconx"),Q("FILEUP-ICON-"+e).classList.remove("fileicontransfer"),Q("FILEUP-ICON-"+e).classList.remove("fileicondone"),Q("FILEUP-ICON-"+e).classList.add(["fileicon","fileiconx","fileicontransfer","fileicondone"][t])),n&&(QS("FILEUP-PROGRESS-"+e).width=n+"px"),i&&(QS("FILEUP-PROGRESS-"+e)["background-color"]=i)}function data2blob(e){for(var t=new Array(e.length),n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return new Blob([new Uint8Array(t)])}function saveFileTransfer(e){var t=fileDownloads[e];t&&1==t.done&&saveAs(data2blob(t.data),t.name)}function cancelFileTransfer(e){null!=currentFileUpload&&currentFileUpload.id==e&&(currentFileUpload=null),null!=currentFileDownload&&currentFileDownload.id==e&&(currentFileDownload=null);var t=!1;if(fileDownloads[e]&&1!=fileDownloads[e].done)delete fileDownloads[e],t=!0;else for(var n in fileUploads)if(fileUploads[n].id==e){send({action:"fileUploadCancel",id:e}),fileUploads.splice(n,1),t=!0;break}t&&changeFileInfo(e,1,200,"gray")}function cancelAllFileTransfers(){for(var e in fileDownloads)cancelFileTransfer(fileDownloads[e].id);for(var e in fileUploads)cancelFileTransfer(fileUploads[e].id)}function continueFileUpload(){if(null==currentFileUpload){if(0==fileUploads.length)return;(currentFileUpload=fileUploads[0]).ptr=0,send({action:"fileUploadStart",size:currentFileUpload.size,id:currentFileUpload.id,type:currentFileUpload.type,name:currentFileUpload.name})}else if(currentFileUpload.size<=currentFileUpload.ptr)send({action:"fileUploadEnd",size:currentFileUpload.size,id:currentFileUpload.id,type:currentFileUpload.type,name:currentFileUpload.name}),changeFileInfo(currentFileUpload.id,3,200),fileUploads.splice(0,1),currentFileUpload=null,continueFileUpload();else{var e=Math.min(4e3,currentFileUpload.data.length-currentFileUpload.ptr),t=currentFileUpload.data.substring(currentFileUpload.ptr,currentFileUpload.ptr+e);send({action:"fileData",id:currentFileUpload.id,data:t}),currentFileUpload.ptr+=e,changeFileInfo(currentFileUpload.id,0,200*currentFileUpload.ptr/currentFileUpload.size)}}function continueFileDownload(e){send({action:"fileUploadAck",id:e.id})}function enableNotificationsButtonClick(){return Notification&&Notification.requestPermission().then(function(e){QV("notifyButton","granted"!=e)}),!1}function camButtonClick(){null==localStream&&startLocalStream({video:!0,audio:!0})}function micButtonClick(){null==localStream&&startLocalStream({video:!1,audio:!0})}function hangUpButtonClick(e,t){var n=Q("localVideoCanvas"),i=Q("remoteVideoCanvas"),o=webrtcSessions[1==multiWebRtc?e:0];if(0==e&&null!=webchannel){try{webchannel.close()}catch(e){}webchannel=null}if(o){if(1!=multiWebRtc&&0!=e||(o.ontrack=null,o.onremovetrack=null,o.onremovestream=null,o.onnicecandidate=null,o.oniceconnectionstatechange=null,o.onsignalingstatechange=null,o.onicegatheringstatechange=null,o.onnotificationneeded=null),1==e&&localStream){var a=localStream.getTracks();for(var l in a)a[l].stop();localStream=null}if(2==e&&remoteStream){a=remoteStream.getTracks();for(var l in a)a[l].stop();remoteStream=null}1!=multiWebRtc&&0!=e||(o.close(),delete webrtcSessions[e])}1==e?(n.removeAttribute("src"),n.removeAttribute("srcObject"),null!=localStream&&(localStream=null),displayLocalVideo(!1)):2==e&&(i.removeAttribute("src"),i.removeAttribute("srcObject"),displayRemoteVideo(!1)),1!=t&&send({action:"videoStop",id:e}),updateControls()}function startLocalStream(a){var l=1==multiWebRtc?1:0;null==localStream&&(1==multiWebRtc&&null!=webrtcSessions[1]||navigator.mediaDevices.getUserMedia&&(localStream=1,updateControls(),navigator.mediaDevices.getUserMedia(a).then(function(e){var t=(localStream=e).getTracks(),n=startWebRTC(l);if(1==a.video){var i=Q("localVideoCanvas");i.srcObject=e,i.onloadedmetadata=function(e){i.play()},displayLocalVideo(!0)}for(var o in t)n.addTrack(t[o],localStream)},function(e){displayControl(e.message+"."),hangUpButtonClick(1)})))}function start(){if(updateControls(),"string"==typeof args.id&&0<args.id.length){var e=window.location.protocol.replace("http","ws")+"//"+window.location.host+window.location.pathname.substring(0,window.location.pathname.lastIndexOf("/"))+"/meshrelay.ashx?id="+args.id;null!=args.auth&&""!=args.auth&&(e+="&auth="+args.auth),(socket=new WebSocket(e)).onopen=function(){state=1,displayControl("Waiting for other user...")},socket.onerror=function(e){},socket.onclose=function(){disconnect()},socket.onmessage=function(e){if(state<2&&"string"==typeof e.data&&("c"==e.data||"cr"==e.data))return hangUpButtonClick(0,!0),hangUpButtonClick(1,!0),hangUpButtonClick(2,!0),displayControl("Connected."),state=2,updateControls(),void sendws({action:"random",random:random});2==state&&processMessage(e.data,1)}}else displayControl("Error: No connection key specified.")}function onUnLoad(){for(var e=0;e<3;e++)webrtcSessions[e]&&(webrtcSessions[e].close(),delete webrtcSessions[e]);if(null!=webchannel){try{webchannel.close()}catch(e){}webchannel=null}if(null!=socket){try{socket.close()}catch(e){}socket=null}}args.title&&(QH("xtitle",args.title.split(" ").join("&nbsp")),document.title=document.title+" - "+args.title),Notification&&QV("notifyButton","granted"!=Notification.permission),document.addEventListener("dragover",haltEvent,!1),document.addEventListener("dragleave",haltEvent,!1),document.addEventListener("drop",fileDrop,!1),document.onclick=function(e){Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null)},document.onkeyup=function(e){if(Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null),2==state&&8==e.keyCode&&0==userInputFocus){var t=Q("xouttext").value;0<t.length&&(Q("xouttext").value=t.substring(0,t.length-1))}if(0==userInputFocus)return haltEvent(e),!1},document.onkeypress=function(e){if(Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null),2==state&&(13==e.keyCode?xsend(e):0==userInputFocus&&1==e.key.length&&(Q("xouttext").value=Q("xouttext").value+e.key)),0==userInputFocus)return haltEvent(e),!1},FileReader.prototype.readAsBinaryString||(FileReader.prototype.readAsBinaryString=function(e){var i="",o=this,a=new FileReader;a.onload=function(e){for(var t=new Uint8Array(a.result),n=0;n<t.byteLength;n++)i+=String.fromCharCode(t[n]);o.onload({target:{result:i}})},a.readAsArrayBuffer(e)}),start()</script>
\ No newline at end of file
views/messenger.handlebars
+9 -8
@@ -12,13 +12,14 @@
12 </head>
13 <body style="font-family:Arial,Helvetica,sans-serif">
14 <div id="xtop" style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray">
15 - <div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Enable browser notification" onclick="enableNotificationsButtonClick()"></div>
16 - <div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
17 - <div id="camButton" class="icon2 topButton" title="Activate camera & microphone" style="display:none" onclick="camButtonClick()"></div>
18 - <div id="micButton" class="icon6 topButton" title="Activate microphone" style="display:none" onclick="micButtonClick()"></div>
19 - <div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
20 - <div style="display:inline-block;width:2px"></div>
21 - <div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b>MeshMessenger<span id="xtitle"></span></b></div>
15 + <div style="position:absolute;background-color:#036;right:0;height:38px">
16 + <div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Enable browser notification" onclick="enableNotificationsButtonClick()"></div>
17 + <div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
18 + <div id="camButton" class="icon2 topButton" title="Activate camera & microphone" style="display:none" onclick="camButtonClick()"></div>
19 + <div id="micButton" class="icon6 topButton" title="Activate microphone" style="display:none" onclick="micButtonClick()"></div>
20 + <div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
21 + </div>
22 + <div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b><span id="xtitle">MeshMessenger</span></b></div>
23 </div>
24 <div id="xmiddle" style="position:absolute;left:0;right:0;top:38px;bottom:30px">
25 <div style="position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll">
@@ -65,7 +66,7 @@
66 var currentFileDownload = null;
67
68 // Set the title
68 - if (args.title) { QH('xtitle', ' - ' + args.title); document.title = document.title + ' - ' + args.title; }
69 + if (args.title) { QH('xtitle', args.title.split(' ').join('&nbsp')); document.title = document.title + ' - ' + args.title; }
70
71 // Setup web notifications
72 if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
views/translations/default-min_fr.handlebars
+15 -6
@@ -3524,7 +3524,7 @@
3524 if (xxdialogMode) return;
3525 var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
3526 if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
3527 - window.open(url, 'meshmessenger:' + currentNode._id);
3527 + window.open(url, 'meshmessenger:' + currentNode._id, 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=400,height=560');
3528 meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
3529 }
3530
@@ -6740,12 +6740,12 @@
6740 var h = '';
6741 if (f.t < 3 || f.t == 4) {
6742 var right = (f.t == 1 || f.t == 4)?p5getQuotabar(f):'', title = '';
6743 - h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + name + '\'>&nbsp;<span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
6743 + h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + name + '">&nbsp;<span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
6744 } else {
6745 var link = shortname, publiclink = '';
6746 - if (publicfolder) { publiclink = ' (<a style=cursor:pointer title=\"Display public link\" onclick=\'return p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>' + "Link" + '</a>)'; }
6747 - if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" download href=\"downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '\">' + shortname + '</a>' + publiclink; }
6748 - h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'>&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
6746 + if (publicfolder) { publiclink = ' (<a style=cursor:pointer title="Display public link" onclick=\'return p5showPublicLink("' + publicPath + '/' + f.nx + '")\'>' + "Link" + '</a>)'; }
6747 + if (f.s > 0) { link = '<a rel="noreferrer noopener" target="_blank" download href="downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '">' + shortname + '</a>' + publiclink; }
6748 + h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + f.nx + '">&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
6749 }
6750
6751 if (f.t < 3) { html1 += h; } else { html2 += h; }
@@ -6883,7 +6883,16 @@
6883 */
6884
6885 var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
6886 - function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
6886 + function p5copyFile(cut) {
6887 + var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation);
6888 + for (var i = 0; i < checkboxes.length; i++) {
6889 + if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) {
6890 + console.log('yy', checkboxes[i].value);
6891 + p5clipboard.push(checkboxes[i].value);
6892 + }
6893 + }
6894 + p5updateClipview();
6895 + }
6896 function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Confim {0} of {1} entrie{2} to this location?", (p5clipboardCut == 0?'copy':'move'), p5clipboard.length, ((p5clipboard.length > 1)?'s':'')) } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
6897 function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0?'copy':'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
6898 function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Holding {0} entrie{1} for {2}", p5clipboard.length, ((p5clipboard.length > 1)?'s':''), (p5clipboardCut == 0?"copy":"move")) + ', <a href=# onclick="return p5clearClip()" style=cursor:pointer>' + "Clear" + '</a>.' } QH('p5bottomstatus', x); p5setActions(); }
views/translations/default_fr.handlebars
+15 -6
@@ -4504,7 +4504,7 @@
4504 if (xxdialogMode) return;
4505 var url = '/messenger?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name;
4506 if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; }
4507 - window.open(url, 'meshmessenger:' + currentNode._id);
4507 + window.open(url, 'meshmessenger:' + currentNode._id, 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=400,height=560');
4508 meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
4509 }
4510
@@ -7720,12 +7720,12 @@
7720 var h = '';
7721 if (f.t < 3 || f.t == 4) {
7722 var right = (f.t == 1 || f.t == 4)?p5getQuotabar(f):'', title = '';
7723 - h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + name + '\'>&nbsp;<span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
7723 + h = '<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + name + '">&nbsp;<span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p5folderset(\"' + encodeURIComponent(f.nx) + '\")></div><a href=# style=cursor:pointer onclick=\'return p5folderset(\"' + encodeURIComponent(f.nx) + '\")\'>' + shortname + '</a></span></div>';
7724 } else {
7725 var link = shortname, publiclink = '';
7726 - if (publicfolder) { publiclink = ' (<a style=cursor:pointer title=\"Display public link\" onclick=\'return p5showPublicLink(\"' + publicPath + '/' + f.nx + '\")\'>' + "Link" + '</a>)'; }
7727 - if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" download href=\"downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '\">' + shortname + '</a>' + publiclink; }
7728 - h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'>&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
7726 + if (publicfolder) { publiclink = ' (<a style=cursor:pointer title="Display public link" onclick=\'return p5showPublicLink("' + publicPath + '/' + f.nx + '")\'>' + "Link" + '</a>)'; }
7727 + if (f.s > 0) { link = '<a rel="noreferrer noopener" target="_blank" download href="downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '">' + shortname + '</a>' + publiclink; }
7728 + h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value="' + f.nx + '">&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
7729 }
7730
7731 if (f.t < 3) { html1 += h; } else { html2 += h; }
@@ -7863,7 +7863,16 @@
7863 */
7864
7865 var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
7866 - function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
7866 + function p5copyFile(cut) {
7867 + var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation);
7868 + for (var i = 0; i < checkboxes.length; i++) {
7869 + if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) {
7870 + console.log('yy', checkboxes[i].value);
7871 + p5clipboard.push(checkboxes[i].value);
7872 + }
7873 + }
7874 + p5updateClipview();
7875 + }
7876 function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Confim {0} of {1} entrie{2} to this location?", (p5clipboardCut == 0?'copy':'move'), p5clipboard.length, ((p5clipboard.length > 1)?'s':'')) } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
7877 function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0?'copy':'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
7878 function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = format("Holding {0} entrie{1} for {2}", p5clipboard.length, ((p5clipboard.length > 1)?'s':''), (p5clipboardCut == 0?"copy":"move")) + ', <a href=# onclick="return p5clearClip()" style=cursor:pointer>' + "Clear" + '</a>.' } QH('p5bottomstatus', x); p5setActions(); }
views/translations/messenger-min_fr.handlebars
+1 -1
@@ -1 +1 @@
1 -<!doctypehtml><html style=height:100%><title>MeshMessenger</title><meta http-equiv=X-UA-Compatible content="IE=edge"><meta content="text/html;charset=utf-8"http-equiv=Content-Type><meta name=format-detection content="telephone=no"><link type=text/css href=styles/style.css media=screen rel=stylesheet title=CSS><link type=text/css href=styles/messenger.css media=screen rel=stylesheet title=CSS><script src=scripts/common-0.0.1.js></script><script src=scripts/filesaver.js></script><body style=font-family:Arial,Helvetica,sans-serif><div id=xtop style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray"><div id=notifyButton class="icon13 topButton"style=margin-right:4px;display:none title="Enable browser notification"onclick=enableNotificationsButtonClick()></div><div id=fileButton class="icon4 topButton"title="Share a file"style=display:none onclick=fileButtonClick()></div><div id=camButton class="icon2 topButton"title="Activer caméra et microphone"style=display:none onclick=camButtonClick()></div><div id=micButton class="icon6 topButton"title="Activer le microphone"style=display:none onclick=micButtonClick()></div><div id=hangupButton class="icon11 topRedButton"title="Hang up"style=display:none onclick=hangUpButtonClick(1)></div><div style=display:inline-block;width:2px></div><div style=padding-top:9px;padding-left:6px;font-size:20px;display:inline-block><b>MeshMessenger<span id=xtitle></span></b></div></div><div id=xmiddle style=position:absolute;left:0;right:0;top:38px;bottom:30px><div style=position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll><div id=xmsg style=position:absolute;left:0;right:0;bottom:0;padding:5px></div></div></div><div id=xbottom style=position:absolute;left:0;right:0;bottom:0;height:30px;background-color:#036><div style=position:absolute;left:5px;right:215px;bottom:4px;top:4px;background-color:#f0f8ff><input id=xouttext style="width:calc(100% - 5px)"onfocus=onUserInputFocus(1) onblur=onUserInputFocus(0)></div><input type=button id=sendButton value=Envoyer style=position:absolute;right:110px;width:100px;top:4px onclick=xsend(event)> <input type=button id=clearButton value=Clear style=position:absolute;right:5px;width:100px;top:4px onclick=displayClear()></div><div id=remoteVideo style="position:absolute;right:24px;top:45px;width:320px;height:calc(240px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none"><div style=position:absolute;right:0;left:0;top:2.5px;text-align:center>Remote</div><video id=remoteVideoCanvas autoplay style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:#000"></video></div><div id=localVideo style="position:absolute;right:24px;top:320px;width:160px;height:calc(120px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none"><div style=position:absolute;right:0;left:0;top:2.5px;text-align:center>Local</div><video id=localVideoCanvas autoplay muted style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:#000"></video></div><input id=uploadFileInput type=file multiple style=display:none><script onunload=onUnLoad()>var userInputFocus=0,args=parseUriArgs(),socket=null,state=0,random=Math.random(),webrtcSessions={},webchannel=null,localStream=null,remoteStream=null,multiWebRtc=!0,userMediaSupport=0,notification=null;getUserMediaSupport(function(e){userMediaSupport=e});var webrtcconfiguration="{{{webrtconfig}}}";if(""==webrtcconfiguration)webrtcconfiguration=null;else try{webrtcconfiguration=JSON.parse(decodeURIComponent(webrtcconfiguration))}catch(e){console.log('Invalid WebRTC config: "'+webrtcconfiguration+'".'),webrtcconfiguration=null}var fileUploads=[],fileDownloads={},currentFileUpload=null,currentFileDownload=null;function onUserInputFocus(e){userInputFocus=e}function displayClear(){QH("xmsg",""),cancelAllFileTransfers(),fileUploads=[],fileDownloads={}}function getUserMediaSupport(i){try{navigator.mediaDevices.enumerateDevices().then(function(e){try{var t=0,n=0;e.forEach(function(e){"audioinput"===e.kind&&(t=1),"videoinput"===e.kind&&(n=1)}),0==t&&i(0),i(t+n)}catch(e){}})}catch(e){}}function displayControl(e){QA("xmsg",'<div style="clear:both"><div style="color:gray;float:left;margin-bottom:2px">'+e+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight}function displayLocalVideo(e){QV("localVideo",e),adjustVideoWindows()}function displayRemoteVideo(e){QV("remoteVideo",e),adjustVideoWindows()}function adjustVideoWindows(){var e="none"!=QS("remoteVideo").display;QS("localVideo").top=e?"320px":"45px"}function displayRemote(e){QA("xmsg",'<div style="clear:both"><div class="remoteBubble">'+e+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,Notification&&QV("notifyButton","granted"!=Notification.permission),Notification&&"granted"==Notification.permission&&(null!=notification&&(notification.close(),notification=null),notification=args.title?new Notification("MeshMessenger - "+args.title,{body:e}):new Notification("MeshMessenger",{body:e}))}function xsend(e){null!=notification&&(notification.close(),notification=null),Notification&&QV("notifyButton","granted"!=Notification.permission);var t=Q("xouttext").value;0<t.length&&(Q("xouttext").value="",QA("xmsg",'<div style="clear:both"><div class="localBubble">'+t+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,send({action:"chat",msg:t}))}function haltEvent(e){return e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),!1}function parseUriArgs(){var e,t={},n=window.document.location.href.split(/[\?&|\=]/);for(i in n.splice(0,1),n)switch(i%2){case 0:e=decodeURIComponent(n[i]);break;case 1:t[e]=decodeURIComponent(n[i]);var i=parseInt(t[e]);i==t[e]&&(t[e]=i)}return t}function updateControls(){QE("sendButton",2==state),QE("clearButton",2==state),QE("xouttext",2==state),QV("fileButton",2==state),QV("camButton",webchannel&&webchannel.ok&&!localStream&&2==userMediaSupport),QV("micButton",webchannel&&webchannel.ok&&!localStream&&0<userMediaSupport),QV("hangupButton",webchannel&&webchannel.ok&&localStream)}function startWebRTC(t,e){if(null!=webrtcSessions[0]&&0==multiWebRtc)return webrtcSessions[0];var n=null;return"undefined"!=typeof RTCPeerConnection?n=new RTCPeerConnection(webrtcconfiguration):"undefined"!=typeof webkitRTCPeerConnection&&(n=new webkitRTCPeerConnection(webrtcconfiguration)),null==n?null:(n.id=t,n.onicecandidate=function(e){try{null!=e.candidate&&sendws({action:"webRtcIce",ice:e.candidate,id:this.id})}catch(e){}},n.oniceconnectionstatechange=function(){n&&"failed"==n.iceConnectionState&&(n.close(),webrtcSessions[n.id]&&delete webrtcSessions[n.id])},n.ondatachannel=function(e){(webchannel=e.channel).onmessage=function(e){processMessage(e.data,2)},webchannel.onopen=function(){webchannel.ok=!0,updateControls(),sendws({action:"rtcSwitch",v:0})},webchannel.onclose=function(e){webchannel&&webchannel.ok?disconnect():hangUpButtonClick(0)}},n.onnegotiationneeded=function(e){null==n.holdTimer&&(n.holdTimer=setTimeout(function(){n.holdTimer=null,n.createOffer(function(e){n.setLocalDescription(e,function(){sendws({action:"webRtcSdp",sdp:e,id:t})},function(){hangUpButtonClick(t)})},function(){hangUpButtonClick(t)})},20))},n.ontrack=function(e){var t=Q("remoteVideoCanvas");t.srcObject=remoteStream=e.streams[0],t.onloadedmetadata=function(e){t.play()},displayRemoteVideo(!0)},1==e&&((webchannel=n.createDataChannel("DataChannel",{})).onmessage=function(e){processMessage(e.data,2)},webchannel.onopen=function(){webchannel.ok=!0,updateControls(),sendws({action:"rtcSwitch",v:0})},webchannel.onclose=function(e){webchannel&&webchannel.ok?disconnect():hangUpButtonClick(0)}),webrtcSessions[t]=n)}function webRtcHandleOffer(i,e){var t=webrtcSessions[i];t&&t.setRemoteDescription(new RTCSessionDescription(e),function(){"offer"==e.type&&t.createAnswer(function(n){t.setLocalDescription(n,function(e,t){try{sendws({action:"webRtcSdp",sdp:n,id:i})}catch(e){}},function(){hangUpButtonClick(i)})},function(){hangUpButtonClick(i)})},function(){hangUpButtonClick(i)})}function performWebRtcSwitch(){webchannel&&webchannel.ok&&(sendws({action:"rtcSwitch",v:1}),webchannel.xoutBuffer=[])}function disconnect(){0<state&&displayControl("Connection closed."),1<state&&setTimeout(start,500),cancelAllFileTransfers(),hangUpButtonClick(0,!0),hangUpButtonClick(1,!0),hangUpButtonClick(2,!0),null!=socket&&(socket.close(),socket=null),updateControls(),state=0}function send(e){if(2==state)if("object"==typeof e&&(e=JSON.stringify(e)),webchannel&&webchannel.ok)null!=webchannel.xoutBuffer?webchannel.xoutBuffer.push(e):webchannel.send(e);else if(null!=socket)try{socket.send(e)}catch(e){}}function sendws(e){2==state&&("object"==typeof e&&(e=JSON.stringify(e)),null!=socket&&socket.send(e))}function webRtcIdSwitch(e){return 0==e?0:3-e}function processMessage(t,e){if("string"==typeof t){try{t=JSON.parse(t)}catch(e){return void console.log("Unable to parse",t)}switch(t.action){case"chat":displayRemote(t.msg);break;case"random":random>t.random&&startWebRTC(0,!0);break;case"webRtcSdp":webrtcSessions[webRtcIdSwitch(t.id)]||startWebRTC(webRtcIdSwitch(t.id),!1),webRtcHandleOffer(webRtcIdSwitch(t.id),t.sdp);break;case"webRtcIce":var n=webrtcSessions[webRtcIdSwitch(t.id)];if(n)try{n.addIceCandidate(new RTCIceCandidate(t.ice))}catch(e){}break;case"videoStop":hangUpButtonClick(webRtcIdSwitch(t.id),!0);break;case"rtcSwitch":switch(t.v){case 0:performWebRtcSwitch();break;case 1:sendws({action:"rtcSwitch",v:2});break;case 2:for(var i in webchannel.xoutBuffer)webchannel.send(webchannel.xoutBuffer[i]);delete webchannel.xoutBuffer;break;default:console.log("Unknown rtcSwitch value: "+t.action)}break;case"file":startFileDownload(t);break;case"fileUploadCancel":cancelFileTransfer(t.id);break;case"fileUploadStart":fileDownloads[t.id]&&((currentFileDownload=fileDownloads[t.id]).data="",changeFileInfo(t.id,2,0),continueFileDownload(t),send({action:"fileUploadAck",id:t.id}));break;case"fileUploadEnd":currentFileDownload&&currentFileDownload.id==t.id&&(changeFileInfo(t.id,3,200),currentFileDownload.done=1,currentFileDownload=null,send({action:"fileUploadAck",id:t.id})),currentFileDownload=null;break;case"fileUploadAck":continueFileUpload();break;case"fileData":currentFileDownload&&currentFileDownload.id==t.id&&(currentFileDownload.data+=t.data,changeFileInfo(t.id,2,200*currentFileDownload.data.length/currentFileDownload.size),send({action:"fileUploadAck",id:t.id}));break;default:console.log("Unhandled object data",t)}}else console.log("Unhandled data",typeof t,t)}function fileButtonClick(){var e=Q("uploadFileInput");1!=e.getAttribute("eventset")&&(e.setAttribute("eventset","1"),e.addEventListener("change",fileSelect,!1)),e.value=null,e.click()}function fileSelect(){if(2==state){var e=Q("uploadFileInput");if(10<e.files.length)displayControl("Limit of 10 file uploads at the same time.");else for(var t=0;t<e.files.length;t++)if(0<e.files[t].size){var n=new FileReader;n.onload=function(e){this.xfile.data=e.target.result,startFileUpload(this.xfile)},n.xfile=e.files[t],n.readAsBinaryString(e.files[t])}}}function fileDrop(e){if(haltEvent(e),2==state&&null!=e.dataTransfer)if(10<e.dataTransfer.files.length)displayControl("Limit of 10 file uploads at the same time.");else for(var t=0;t<e.dataTransfer.files.length;t++)if(0<e.dataTransfer.files[t].size){var n=new FileReader;n.onload=function(e){this.xfile.data=e.target.result,startFileUpload(this.xfile)},n.xfile=e.dataTransfer.files[t],n.readAsBinaryString(e.dataTransfer.files[t])}}function startFileUpload(e){2==state&&(e.id=Math.random(),fileUploads.push(e),QA("xmsg",'<div style="clear:both"></div><div id="FILEUP-'+e.id+'" class="localBubble" style="width:240px;cursor:pointer" onclick="cancelFileTransfer(\''+e.id+'\')"><div id="FILEUP-ICON-'+e.id+'" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-'+e.id+'" style="height:16px;overflow:hidden;white-space:nowrap;" title="'+e.name+'">'+e.name+'</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-'+e.id+'" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>'),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,send({action:"file",size:e.size,id:e.id,type:e.type,name:e.name}),null==currentFileUpload&&continueFileUpload())}function startFileDownload(e){2==state&&(fileDownloads[e.id]=e,QA("xmsg",'<div style="clear:both"></div><div id="FILEUP-'+e.id+'" class="remoteBubble" style="width:240px;cursor:pointer" onclick="saveFileTransfer(\''+e.id+'\')"><div id="FILEUP-ICON-'+e.id+'" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-'+e.id+'" style="height:16px;overflow:hidden;white-space:nowrap;" title="'+e.name+'">'+e.name+'</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-'+e.id+'" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>'),Q("xmsg").scrollTop=Q("xmsg").scrollHeight)}function changeFileInfo(e,t,n,i){t&&(Q("FILEUP-ICON-"+e).classList.remove("fileicon"),Q("FILEUP-ICON-"+e).classList.remove("fileiconx"),Q("FILEUP-ICON-"+e).classList.remove("fileicontransfer"),Q("FILEUP-ICON-"+e).classList.remove("fileicondone"),Q("FILEUP-ICON-"+e).classList.add(["fileicon","fileiconx","fileicontransfer","fileicondone"][t])),n&&(QS("FILEUP-PROGRESS-"+e).width=n+"px"),i&&(QS("FILEUP-PROGRESS-"+e)["background-color"]=i)}function data2blob(e){for(var t=new Array(e.length),n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return new Blob([new Uint8Array(t)])}function saveFileTransfer(e){var t=fileDownloads[e];t&&1==t.done&&saveAs(data2blob(t.data),t.name)}function cancelFileTransfer(e){null!=currentFileUpload&&currentFileUpload.id==e&&(currentFileUpload=null),null!=currentFileDownload&&currentFileDownload.id==e&&(currentFileDownload=null);var t=!1;if(fileDownloads[e]&&1!=fileDownloads[e].done)delete fileDownloads[e],t=!0;else for(var n in fileUploads)if(fileUploads[n].id==e){send({action:"fileUploadCancel",id:e}),fileUploads.splice(n,1),t=!0;break}t&&changeFileInfo(e,1,200,"gray")}function cancelAllFileTransfers(){for(var e in fileDownloads)cancelFileTransfer(fileDownloads[e].id);for(var e in fileUploads)cancelFileTransfer(fileUploads[e].id)}function continueFileUpload(){if(null==currentFileUpload){if(0==fileUploads.length)return;(currentFileUpload=fileUploads[0]).ptr=0,send({action:"fileUploadStart",size:currentFileUpload.size,id:currentFileUpload.id,type:currentFileUpload.type,name:currentFileUpload.name})}else if(currentFileUpload.size<=currentFileUpload.ptr)send({action:"fileUploadEnd",size:currentFileUpload.size,id:currentFileUpload.id,type:currentFileUpload.type,name:currentFileUpload.name}),changeFileInfo(currentFileUpload.id,3,200),fileUploads.splice(0,1),currentFileUpload=null,continueFileUpload();else{var e=Math.min(4e3,currentFileUpload.data.length-currentFileUpload.ptr),t=currentFileUpload.data.substring(currentFileUpload.ptr,currentFileUpload.ptr+e);send({action:"fileData",id:currentFileUpload.id,data:t}),currentFileUpload.ptr+=e,changeFileInfo(currentFileUpload.id,0,200*currentFileUpload.ptr/currentFileUpload.size)}}function continueFileDownload(e){send({action:"fileUploadAck",id:e.id})}function enableNotificationsButtonClick(){return Notification&&Notification.requestPermission().then(function(e){QV("notifyButton","granted"!=e)}),!1}function camButtonClick(){null==localStream&&startLocalStream({video:!0,audio:!0})}function micButtonClick(){null==localStream&&startLocalStream({video:!1,audio:!0})}function hangUpButtonClick(e,t){var n=Q("localVideoCanvas"),i=Q("remoteVideoCanvas"),o=webrtcSessions[1==multiWebRtc?e:0];if(0==e&&null!=webchannel){try{webchannel.close()}catch(e){}webchannel=null}if(o){if(1!=multiWebRtc&&0!=e||(o.ontrack=null,o.onremovetrack=null,o.onremovestream=null,o.onnicecandidate=null,o.oniceconnectionstatechange=null,o.onsignalingstatechange=null,o.onicegatheringstatechange=null,o.onnotificationneeded=null),1==e&&localStream){var a=localStream.getTracks();for(var l in a)a[l].stop();localStream=null}if(2==e&&remoteStream){a=remoteStream.getTracks();for(var l in a)a[l].stop();remoteStream=null}1!=multiWebRtc&&0!=e||(o.close(),delete webrtcSessions[e])}1==e?(n.removeAttribute("src"),n.removeAttribute("srcObject"),null!=localStream&&(localStream=null),displayLocalVideo(!1)):2==e&&(i.removeAttribute("src"),i.removeAttribute("srcObject"),displayRemoteVideo(!1)),1!=t&&send({action:"videoStop",id:e}),updateControls()}function startLocalStream(a){var l=1==multiWebRtc?1:0;null==localStream&&(1==multiWebRtc&&null!=webrtcSessions[1]||navigator.mediaDevices.getUserMedia&&(localStream=1,updateControls(),navigator.mediaDevices.getUserMedia(a).then(function(e){var t=(localStream=e).getTracks(),n=startWebRTC(l);if(1==a.video){var i=Q("localVideoCanvas");i.srcObject=e,i.onloadedmetadata=function(e){i.play()},displayLocalVideo(!0)}for(var o in t)n.addTrack(t[o],localStream)},function(e){displayControl(e.message+"."),hangUpButtonClick(1)})))}function start(){if(updateControls(),"string"==typeof args.id&&0<args.id.length){var e=window.location.protocol.replace("http","ws")+"//"+window.location.host+window.location.pathname.substring(0,window.location.pathname.lastIndexOf("/"))+"/meshrelay.ashx?id="+args.id;null!=args.auth&&""!=args.auth&&(e+="&auth="+args.auth),(socket=new WebSocket(e)).onopen=function(){state=1,displayControl("Waiting for other user...")},socket.onerror=function(e){},socket.onclose=function(){disconnect()},socket.onmessage=function(e){if(state<2&&"string"==typeof e.data&&("c"==e.data||"cr"==e.data))return hangUpButtonClick(0,!0),hangUpButtonClick(1,!0),hangUpButtonClick(2,!0),displayControl("Connected."),state=2,updateControls(),void sendws({action:"random",random:random});2==state&&processMessage(e.data,1)}}else displayControl("Error: No connection key specified.")}function onUnLoad(){for(var e=0;e<3;e++)webrtcSessions[e]&&(webrtcSessions[e].close(),delete webrtcSessions[e]);if(null!=webchannel){try{webchannel.close()}catch(e){}webchannel=null}if(null!=socket){try{socket.close()}catch(e){}socket=null}}args.title&&(QH("xtitle"," - "+args.title),document.title=document.title+" - "+args.title),Notification&&QV("notifyButton","granted"!=Notification.permission),document.addEventListener("dragover",haltEvent,!1),document.addEventListener("dragleave",haltEvent,!1),document.addEventListener("drop",fileDrop,!1),document.onclick=function(e){Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null)},document.onkeyup=function(e){if(Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null),2==state&&8==e.keyCode&&0==userInputFocus){var t=Q("xouttext").value;0<t.length&&(Q("xouttext").value=t.substring(0,t.length-1))}if(0==userInputFocus)return haltEvent(e),!1},document.onkeypress=function(e){if(Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null),2==state&&(13==e.keyCode?xsend(e):0==userInputFocus&&1==e.key.length&&(Q("xouttext").value=Q("xouttext").value+e.key)),0==userInputFocus)return haltEvent(e),!1},FileReader.prototype.readAsBinaryString||(FileReader.prototype.readAsBinaryString=function(e){var i="",o=this,a=new FileReader;a.onload=function(e){for(var t=new Uint8Array(a.result),n=0;n<t.byteLength;n++)i+=String.fromCharCode(t[n]);o.onload({target:{result:i}})},a.readAsArrayBuffer(e)}),start()</script>
\ No newline at end of file
1 +<!doctypehtml><html style=height:100%><title>MeshMessenger</title><meta http-equiv=X-UA-Compatible content="IE=edge"><meta content="text/html;charset=utf-8"http-equiv=Content-Type><meta name=format-detection content="telephone=no"><link type=text/css href=styles/style.css media=screen rel=stylesheet title=CSS><link type=text/css href=styles/messenger.css media=screen rel=stylesheet title=CSS><script src=scripts/common-0.0.1.js></script><script src=scripts/filesaver.js></script><body style=font-family:Arial,Helvetica,sans-serif><div id=xtop style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray"><div style=position:absolute;background-color:#036;right:0;height:38px><div id=notifyButton class="icon13 topButton"style=margin-right:4px;display:none title="Enable browser notification"onclick=enableNotificationsButtonClick()></div><div id=fileButton class="icon4 topButton"title="Share a file"style=display:none onclick=fileButtonClick()></div><div id=camButton class="icon2 topButton"title="Activer caméra et microphone"style=display:none onclick=camButtonClick()></div><div id=micButton class="icon6 topButton"title="Activer le microphone"style=display:none onclick=micButtonClick()></div><div id=hangupButton class="icon11 topRedButton"title="Hang up"style=display:none onclick=hangUpButtonClick(1)></div></div><div style=padding-top:9px;padding-left:6px;font-size:20px;display:inline-block><b><span id=xtitle>MeshMessenger</span></b></div></div><div id=xmiddle style=position:absolute;left:0;right:0;top:38px;bottom:30px><div style=position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll><div id=xmsg style=position:absolute;left:0;right:0;bottom:0;padding:5px></div></div></div><div id=xbottom style=position:absolute;left:0;right:0;bottom:0;height:30px;background-color:#036><div style=position:absolute;left:5px;right:215px;bottom:4px;top:4px;background-color:#f0f8ff><input id=xouttext style="width:calc(100% - 5px)"onfocus=onUserInputFocus(1) onblur=onUserInputFocus(0)></div><input type=button id=sendButton value=Envoyer style=position:absolute;right:110px;width:100px;top:4px onclick=xsend(event)> <input type=button id=clearButton value=Clear style=position:absolute;right:5px;width:100px;top:4px onclick=displayClear()></div><div id=remoteVideo style="position:absolute;right:24px;top:45px;width:320px;height:calc(240px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none"><div style=position:absolute;right:0;left:0;top:2.5px;text-align:center>Remote</div><video id=remoteVideoCanvas autoplay style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:#000"></video></div><div id=localVideo style="position:absolute;right:24px;top:320px;width:160px;height:calc(120px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none"><div style=position:absolute;right:0;left:0;top:2.5px;text-align:center>Local</div><video id=localVideoCanvas autoplay muted style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:#000"></video></div><input id=uploadFileInput type=file multiple style=display:none><script onunload=onUnLoad()>var userInputFocus=0,args=parseUriArgs(),socket=null,state=0,random=Math.random(),webrtcSessions={},webchannel=null,localStream=null,remoteStream=null,multiWebRtc=!0,userMediaSupport=0,notification=null;getUserMediaSupport(function(e){userMediaSupport=e});var webrtcconfiguration="{{{webrtconfig}}}";if(""==webrtcconfiguration)webrtcconfiguration=null;else try{webrtcconfiguration=JSON.parse(decodeURIComponent(webrtcconfiguration))}catch(e){console.log('Invalid WebRTC config: "'+webrtcconfiguration+'".'),webrtcconfiguration=null}var fileUploads=[],fileDownloads={},currentFileUpload=null,currentFileDownload=null;function onUserInputFocus(e){userInputFocus=e}function displayClear(){QH("xmsg",""),cancelAllFileTransfers(),fileUploads=[],fileDownloads={}}function getUserMediaSupport(i){try{navigator.mediaDevices.enumerateDevices().then(function(e){try{var t=0,n=0;e.forEach(function(e){"audioinput"===e.kind&&(t=1),"videoinput"===e.kind&&(n=1)}),0==t&&i(0),i(t+n)}catch(e){}})}catch(e){}}function displayControl(e){QA("xmsg",'<div style="clear:both"><div style="color:gray;float:left;margin-bottom:2px">'+e+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight}function displayLocalVideo(e){QV("localVideo",e),adjustVideoWindows()}function displayRemoteVideo(e){QV("remoteVideo",e),adjustVideoWindows()}function adjustVideoWindows(){var e="none"!=QS("remoteVideo").display;QS("localVideo").top=e?"320px":"45px"}function displayRemote(e){QA("xmsg",'<div style="clear:both"><div class="remoteBubble">'+e+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,Notification&&QV("notifyButton","granted"!=Notification.permission),Notification&&"granted"==Notification.permission&&(null!=notification&&(notification.close(),notification=null),notification=args.title?new Notification("MeshMessenger - "+args.title,{body:e}):new Notification("MeshMessenger",{body:e}))}function xsend(e){null!=notification&&(notification.close(),notification=null),Notification&&QV("notifyButton","granted"!=Notification.permission);var t=Q("xouttext").value;0<t.length&&(Q("xouttext").value="",QA("xmsg",'<div style="clear:both"><div class="localBubble">'+t+"</div><div></div></div>"),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,send({action:"chat",msg:t}))}function haltEvent(e){return e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),!1}function parseUriArgs(){var e,t={},n=window.document.location.href.split(/[\?&|\=]/);for(i in n.splice(0,1),n)switch(i%2){case 0:e=decodeURIComponent(n[i]);break;case 1:t[e]=decodeURIComponent(n[i]);var i=parseInt(t[e]);i==t[e]&&(t[e]=i)}return t}function updateControls(){QE("sendButton",2==state),QE("clearButton",2==state),QE("xouttext",2==state),QV("fileButton",2==state),QV("camButton",webchannel&&webchannel.ok&&!localStream&&2==userMediaSupport),QV("micButton",webchannel&&webchannel.ok&&!localStream&&0<userMediaSupport),QV("hangupButton",webchannel&&webchannel.ok&&localStream)}function startWebRTC(t,e){if(null!=webrtcSessions[0]&&0==multiWebRtc)return webrtcSessions[0];var n=null;return"undefined"!=typeof RTCPeerConnection?n=new RTCPeerConnection(webrtcconfiguration):"undefined"!=typeof webkitRTCPeerConnection&&(n=new webkitRTCPeerConnection(webrtcconfiguration)),null==n?null:(n.id=t,n.onicecandidate=function(e){try{null!=e.candidate&&sendws({action:"webRtcIce",ice:e.candidate,id:this.id})}catch(e){}},n.oniceconnectionstatechange=function(){n&&"failed"==n.iceConnectionState&&(n.close(),webrtcSessions[n.id]&&delete webrtcSessions[n.id])},n.ondatachannel=function(e){(webchannel=e.channel).onmessage=function(e){processMessage(e.data,2)},webchannel.onopen=function(){webchannel.ok=!0,updateControls(),sendws({action:"rtcSwitch",v:0})},webchannel.onclose=function(e){webchannel&&webchannel.ok?disconnect():hangUpButtonClick(0)}},n.onnegotiationneeded=function(e){null==n.holdTimer&&(n.holdTimer=setTimeout(function(){n.holdTimer=null,n.createOffer(function(e){n.setLocalDescription(e,function(){sendws({action:"webRtcSdp",sdp:e,id:t})},function(){hangUpButtonClick(t)})},function(){hangUpButtonClick(t)})},20))},n.ontrack=function(e){var t=Q("remoteVideoCanvas");t.srcObject=remoteStream=e.streams[0],t.onloadedmetadata=function(e){t.play()},displayRemoteVideo(!0)},1==e&&((webchannel=n.createDataChannel("DataChannel",{})).onmessage=function(e){processMessage(e.data,2)},webchannel.onopen=function(){webchannel.ok=!0,updateControls(),sendws({action:"rtcSwitch",v:0})},webchannel.onclose=function(e){webchannel&&webchannel.ok?disconnect():hangUpButtonClick(0)}),webrtcSessions[t]=n)}function webRtcHandleOffer(i,e){var t=webrtcSessions[i];t&&t.setRemoteDescription(new RTCSessionDescription(e),function(){"offer"==e.type&&t.createAnswer(function(n){t.setLocalDescription(n,function(e,t){try{sendws({action:"webRtcSdp",sdp:n,id:i})}catch(e){}},function(){hangUpButtonClick(i)})},function(){hangUpButtonClick(i)})},function(){hangUpButtonClick(i)})}function performWebRtcSwitch(){webchannel&&webchannel.ok&&(sendws({action:"rtcSwitch",v:1}),webchannel.xoutBuffer=[])}function disconnect(){0<state&&displayControl("Connection closed."),1<state&&setTimeout(start,500),cancelAllFileTransfers(),hangUpButtonClick(0,!0),hangUpButtonClick(1,!0),hangUpButtonClick(2,!0),null!=socket&&(socket.close(),socket=null),updateControls(),state=0}function send(e){if(2==state)if("object"==typeof e&&(e=JSON.stringify(e)),webchannel&&webchannel.ok)null!=webchannel.xoutBuffer?webchannel.xoutBuffer.push(e):webchannel.send(e);else if(null!=socket)try{socket.send(e)}catch(e){}}function sendws(e){2==state&&("object"==typeof e&&(e=JSON.stringify(e)),null!=socket&&socket.send(e))}function webRtcIdSwitch(e){return 0==e?0:3-e}function processMessage(t,e){if("string"==typeof t){try{t=JSON.parse(t)}catch(e){return void console.log("Unable to parse",t)}switch(t.action){case"chat":displayRemote(t.msg);break;case"random":random>t.random&&startWebRTC(0,!0);break;case"webRtcSdp":webrtcSessions[webRtcIdSwitch(t.id)]||startWebRTC(webRtcIdSwitch(t.id),!1),webRtcHandleOffer(webRtcIdSwitch(t.id),t.sdp);break;case"webRtcIce":var n=webrtcSessions[webRtcIdSwitch(t.id)];if(n)try{n.addIceCandidate(new RTCIceCandidate(t.ice))}catch(e){}break;case"videoStop":hangUpButtonClick(webRtcIdSwitch(t.id),!0);break;case"rtcSwitch":switch(t.v){case 0:performWebRtcSwitch();break;case 1:sendws({action:"rtcSwitch",v:2});break;case 2:for(var i in webchannel.xoutBuffer)webchannel.send(webchannel.xoutBuffer[i]);delete webchannel.xoutBuffer;break;default:console.log("Unknown rtcSwitch value: "+t.action)}break;case"file":startFileDownload(t);break;case"fileUploadCancel":cancelFileTransfer(t.id);break;case"fileUploadStart":fileDownloads[t.id]&&((currentFileDownload=fileDownloads[t.id]).data="",changeFileInfo(t.id,2,0),continueFileDownload(t),send({action:"fileUploadAck",id:t.id}));break;case"fileUploadEnd":currentFileDownload&&currentFileDownload.id==t.id&&(changeFileInfo(t.id,3,200),currentFileDownload.done=1,currentFileDownload=null,send({action:"fileUploadAck",id:t.id})),currentFileDownload=null;break;case"fileUploadAck":continueFileUpload();break;case"fileData":currentFileDownload&&currentFileDownload.id==t.id&&(currentFileDownload.data+=t.data,changeFileInfo(t.id,2,200*currentFileDownload.data.length/currentFileDownload.size),send({action:"fileUploadAck",id:t.id}));break;default:console.log("Unhandled object data",t)}}else console.log("Unhandled data",typeof t,t)}function fileButtonClick(){var e=Q("uploadFileInput");1!=e.getAttribute("eventset")&&(e.setAttribute("eventset","1"),e.addEventListener("change",fileSelect,!1)),e.value=null,e.click()}function fileSelect(){if(2==state){var e=Q("uploadFileInput");if(10<e.files.length)displayControl("Limit of 10 file uploads at the same time.");else for(var t=0;t<e.files.length;t++)if(0<e.files[t].size){var n=new FileReader;n.onload=function(e){this.xfile.data=e.target.result,startFileUpload(this.xfile)},n.xfile=e.files[t],n.readAsBinaryString(e.files[t])}}}function fileDrop(e){if(haltEvent(e),2==state&&null!=e.dataTransfer)if(10<e.dataTransfer.files.length)displayControl("Limit of 10 file uploads at the same time.");else for(var t=0;t<e.dataTransfer.files.length;t++)if(0<e.dataTransfer.files[t].size){var n=new FileReader;n.onload=function(e){this.xfile.data=e.target.result,startFileUpload(this.xfile)},n.xfile=e.dataTransfer.files[t],n.readAsBinaryString(e.dataTransfer.files[t])}}function startFileUpload(e){2==state&&(e.id=Math.random(),fileUploads.push(e),QA("xmsg",'<div style="clear:both"></div><div id="FILEUP-'+e.id+'" class="localBubble" style="width:240px;cursor:pointer" onclick="cancelFileTransfer(\''+e.id+'\')"><div id="FILEUP-ICON-'+e.id+'" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-'+e.id+'" style="height:16px;overflow:hidden;white-space:nowrap;" title="'+e.name+'">'+e.name+'</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-'+e.id+'" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>'),Q("xmsg").scrollTop=Q("xmsg").scrollHeight,send({action:"file",size:e.size,id:e.id,type:e.type,name:e.name}),null==currentFileUpload&&continueFileUpload())}function startFileDownload(e){2==state&&(fileDownloads[e.id]=e,QA("xmsg",'<div style="clear:both"></div><div id="FILEUP-'+e.id+'" class="remoteBubble" style="width:240px;cursor:pointer" onclick="saveFileTransfer(\''+e.id+'\')"><div id="FILEUP-ICON-'+e.id+'" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-'+e.id+'" style="height:16px;overflow:hidden;white-space:nowrap;" title="'+e.name+'">'+e.name+'</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-'+e.id+'" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>'),Q("xmsg").scrollTop=Q("xmsg").scrollHeight)}function changeFileInfo(e,t,n,i){t&&(Q("FILEUP-ICON-"+e).classList.remove("fileicon"),Q("FILEUP-ICON-"+e).classList.remove("fileiconx"),Q("FILEUP-ICON-"+e).classList.remove("fileicontransfer"),Q("FILEUP-ICON-"+e).classList.remove("fileicondone"),Q("FILEUP-ICON-"+e).classList.add(["fileicon","fileiconx","fileicontransfer","fileicondone"][t])),n&&(QS("FILEUP-PROGRESS-"+e).width=n+"px"),i&&(QS("FILEUP-PROGRESS-"+e)["background-color"]=i)}function data2blob(e){for(var t=new Array(e.length),n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return new Blob([new Uint8Array(t)])}function saveFileTransfer(e){var t=fileDownloads[e];t&&1==t.done&&saveAs(data2blob(t.data),t.name)}function cancelFileTransfer(e){null!=currentFileUpload&&currentFileUpload.id==e&&(currentFileUpload=null),null!=currentFileDownload&&currentFileDownload.id==e&&(currentFileDownload=null);var t=!1;if(fileDownloads[e]&&1!=fileDownloads[e].done)delete fileDownloads[e],t=!0;else for(var n in fileUploads)if(fileUploads[n].id==e){send({action:"fileUploadCancel",id:e}),fileUploads.splice(n,1),t=!0;break}t&&changeFileInfo(e,1,200,"gray")}function cancelAllFileTransfers(){for(var e in fileDownloads)cancelFileTransfer(fileDownloads[e].id);for(var e in fileUploads)cancelFileTransfer(fileUploads[e].id)}function continueFileUpload(){if(null==currentFileUpload){if(0==fileUploads.length)return;(currentFileUpload=fileUploads[0]).ptr=0,send({action:"fileUploadStart",size:currentFileUpload.size,id:currentFileUpload.id,type:currentFileUpload.type,name:currentFileUpload.name})}else if(currentFileUpload.size<=currentFileUpload.ptr)send({action:"fileUploadEnd",size:currentFileUpload.size,id:currentFileUpload.id,type:currentFileUpload.type,name:currentFileUpload.name}),changeFileInfo(currentFileUpload.id,3,200),fileUploads.splice(0,1),currentFileUpload=null,continueFileUpload();else{var e=Math.min(4e3,currentFileUpload.data.length-currentFileUpload.ptr),t=currentFileUpload.data.substring(currentFileUpload.ptr,currentFileUpload.ptr+e);send({action:"fileData",id:currentFileUpload.id,data:t}),currentFileUpload.ptr+=e,changeFileInfo(currentFileUpload.id,0,200*currentFileUpload.ptr/currentFileUpload.size)}}function continueFileDownload(e){send({action:"fileUploadAck",id:e.id})}function enableNotificationsButtonClick(){return Notification&&Notification.requestPermission().then(function(e){QV("notifyButton","granted"!=e)}),!1}function camButtonClick(){null==localStream&&startLocalStream({video:!0,audio:!0})}function micButtonClick(){null==localStream&&startLocalStream({video:!1,audio:!0})}function hangUpButtonClick(e,t){var n=Q("localVideoCanvas"),i=Q("remoteVideoCanvas"),o=webrtcSessions[1==multiWebRtc?e:0];if(0==e&&null!=webchannel){try{webchannel.close()}catch(e){}webchannel=null}if(o){if(1!=multiWebRtc&&0!=e||(o.ontrack=null,o.onremovetrack=null,o.onremovestream=null,o.onnicecandidate=null,o.oniceconnectionstatechange=null,o.onsignalingstatechange=null,o.onicegatheringstatechange=null,o.onnotificationneeded=null),1==e&&localStream){var a=localStream.getTracks();for(var l in a)a[l].stop();localStream=null}if(2==e&&remoteStream){a=remoteStream.getTracks();for(var l in a)a[l].stop();remoteStream=null}1!=multiWebRtc&&0!=e||(o.close(),delete webrtcSessions[e])}1==e?(n.removeAttribute("src"),n.removeAttribute("srcObject"),null!=localStream&&(localStream=null),displayLocalVideo(!1)):2==e&&(i.removeAttribute("src"),i.removeAttribute("srcObject"),displayRemoteVideo(!1)),1!=t&&send({action:"videoStop",id:e}),updateControls()}function startLocalStream(a){var l=1==multiWebRtc?1:0;null==localStream&&(1==multiWebRtc&&null!=webrtcSessions[1]||navigator.mediaDevices.getUserMedia&&(localStream=1,updateControls(),navigator.mediaDevices.getUserMedia(a).then(function(e){var t=(localStream=e).getTracks(),n=startWebRTC(l);if(1==a.video){var i=Q("localVideoCanvas");i.srcObject=e,i.onloadedmetadata=function(e){i.play()},displayLocalVideo(!0)}for(var o in t)n.addTrack(t[o],localStream)},function(e){displayControl(e.message+"."),hangUpButtonClick(1)})))}function start(){if(updateControls(),"string"==typeof args.id&&0<args.id.length){var e=window.location.protocol.replace("http","ws")+"//"+window.location.host+window.location.pathname.substring(0,window.location.pathname.lastIndexOf("/"))+"/meshrelay.ashx?id="+args.id;null!=args.auth&&""!=args.auth&&(e+="&auth="+args.auth),(socket=new WebSocket(e)).onopen=function(){state=1,displayControl("Waiting for other user...")},socket.onerror=function(e){},socket.onclose=function(){disconnect()},socket.onmessage=function(e){if(state<2&&"string"==typeof e.data&&("c"==e.data||"cr"==e.data))return hangUpButtonClick(0,!0),hangUpButtonClick(1,!0),hangUpButtonClick(2,!0),displayControl("Connected."),state=2,updateControls(),void sendws({action:"random",random:random});2==state&&processMessage(e.data,1)}}else displayControl("Error: No connection key specified.")}function onUnLoad(){for(var e=0;e<3;e++)webrtcSessions[e]&&(webrtcSessions[e].close(),delete webrtcSessions[e]);if(null!=webchannel){try{webchannel.close()}catch(e){}webchannel=null}if(null!=socket){try{socket.close()}catch(e){}socket=null}}args.title&&(QH("xtitle",args.title.split(" ").join("&nbsp")),document.title=document.title+" - "+args.title),Notification&&QV("notifyButton","granted"!=Notification.permission),document.addEventListener("dragover",haltEvent,!1),document.addEventListener("dragleave",haltEvent,!1),document.addEventListener("drop",fileDrop,!1),document.onclick=function(e){Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null)},document.onkeyup=function(e){if(Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null),2==state&&8==e.keyCode&&0==userInputFocus){var t=Q("xouttext").value;0<t.length&&(Q("xouttext").value=t.substring(0,t.length-1))}if(0==userInputFocus)return haltEvent(e),!1},document.onkeypress=function(e){if(Notification&&QV("notifyButton","granted"!=Notification.permission),null!=notification&&(notification.close(),notification=null),2==state&&(13==e.keyCode?xsend(e):0==userInputFocus&&1==e.key.length&&(Q("xouttext").value=Q("xouttext").value+e.key)),0==userInputFocus)return haltEvent(e),!1},FileReader.prototype.readAsBinaryString||(FileReader.prototype.readAsBinaryString=function(e){var i="",o=this,a=new FileReader;a.onload=function(e){for(var t=new Uint8Array(a.result),n=0;n<t.byteLength;n++)i+=String.fromCharCode(t[n]);o.onload({target:{result:i}})},a.readAsArrayBuffer(e)}),start()</script>
\ No newline at end of file
views/translations/messenger_fr.handlebars
+9 -8
@@ -10,13 +10,14 @@
10 </head>
11 <body style="font-family:Arial,Helvetica,sans-serif">
12 <div id="xtop" style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray">
13 - <div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Enable browser notification" onclick="enableNotificationsButtonClick()"></div>
14 - <div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
15 - <div id="camButton" class="icon2 topButton" title="Activer caméra et microphone" style="display:none" onclick="camButtonClick()"></div>
16 - <div id="micButton" class="icon6 topButton" title="Activer le microphone" style="display:none" onclick="micButtonClick()"></div>
17 - <div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
18 - <div style="display:inline-block;width:2px"></div>
19 - <div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b>MeshMessenger<span id="xtitle"></span></b></div>
13 + <div style="position:absolute;background-color:#036;right:0;height:38px">
14 + <div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Enable browser notification" onclick="enableNotificationsButtonClick()"></div>
15 + <div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
16 + <div id="camButton" class="icon2 topButton" title="Activer caméra et microphone" style="display:none" onclick="camButtonClick()"></div>
17 + <div id="micButton" class="icon6 topButton" title="Activer le microphone" style="display:none" onclick="micButtonClick()"></div>
18 + <div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
19 + </div>
20 + <div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b><span id="xtitle">MeshMessenger</span></b></div>
21 </div>
22 <div id="xmiddle" style="position:absolute;left:0;right:0;top:38px;bottom:30px">
23 <div style="position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll">
@@ -63,7 +64,7 @@
64 var currentFileDownload = null;
65
66 // Set the title
66 - if (args.title) { QH('xtitle', ' - ' + args.title); document.title = document.title + ' - ' + args.title; }
67 + if (args.title) { QH('xtitle', args.title.split(' ').join('&nbsp')); document.title = document.title + ' - ' + args.title; }
68
69 // Setup web notifications
70 if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
webserver.js
+7 -5
@@ -2691,11 +2691,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2691 // Delete a folder and all sub items. (TODO: try to make all async version)
2692 function deleteFolderRec(path) {
2693 if (obj.fs.existsSync(path) == false) return;
2694 - obj.fs.readdirSync(path).forEach(function (file, index) {
2695 - var pathx = path + "/" + file;
2696 - if (obj.fs.lstatSync(pathx).isDirectory()) { deleteFolderRec(pathx); } else { obj.fs.unlinkSync(pathx); }
2697 - });
2698 - obj.fs.rmdirSync(path);
2694 + try {
2695 + obj.fs.readdirSync(path).forEach(function (file, index) {
2696 + var pathx = path + '/' + file;
2697 + if (obj.fs.lstatSync(pathx).isDirectory()) { deleteFolderRec(pathx); } else { obj.fs.unlinkSync(pathx); }
2698 + });
2699 + obj.fs.rmdirSync(path);
2700 + } catch (ex) { }
2701 }
2702
2703 // Handle Intel AMT events