From e1b93dbd2946d0f6214b6e46cde3a79db5b97a43 Mon Sep 17 00:00:00 2001
From: Ylian Saint-Hilaire
Date: Thu, 13 Aug 2020 12:29:18 -0700
Subject: [PATCH] Improved file upload to device.
---
agents/meshcore.js | 60 +++---
public/scripts/amt-wsman-0.2.0-min.js | 2 +-
translate/translate.json | 253 +++++++++++++-------------
views/default-mobile.handlebars | 164 +++++++++--------
views/default.handlebars | 177 +++++-------------
5 files changed, 301 insertions(+), 355 deletions(-)
diff --git a/agents/meshcore.js b/agents/meshcore.js
index 0986e520..77cf14a7 100644
--- a/agents/meshcore.js
+++ b/agents/meshcore.js
@@ -1268,7 +1268,7 @@ function createMeshCore(agent) {
*/
// If there is a upload or download active on this connection, close the file
- if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
+ if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; delete this.httprequest.uploadFileid; delete this.httprequest.uploadFilePath; }
if (this.httprequest.downloadFile) { fs.closeSync(this.httprequest.downloadFile); delete this.httprequest.downloadFile; }
// Clean up WebRTC
@@ -1291,31 +1291,18 @@ function createMeshCore(agent) {
//sendConsoleText('OnTunnelData, ' + data.length + ', ' + typeof data + ', ' + data);
// If this is upload data, save it to file
- if (this.httprequest.uploadFile) {
- if (typeof data == 'object') {
- // Save the data to file being uploaded.
- if (this.httprequest.uploadFile) {
- try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { sendConsoleText('FileSave ERROR'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
- this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data.
- }
- } else if (typeof data == 'string') {
- // Close the file and confirm. We need to make this added round trip since websocket deflate compression can cause the last message before a websocket close to not be received.
- if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
- this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
- this.end();
+ if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123)) {
+ // Save the data to file being uploaded.
+ if (data[0] == 0) {
+ // If data starts with zero, skip the first byte. This is used to escape binary file data from JSON.
+ try { fs.writeSync(this.httprequest.uploadFile, data, 1, data.length - 1); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
+ } else {
+ // If data does not start with zero, save as-is.
+ try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
}
+ this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data.
return;
}
- /*
- // If this is a download, send more of the file
- if (this.httprequest.downloadFile) {
- var buf = Buffer.alloc(4096);
- var len = fs.readSync(this.httprequest.downloadFile, buf, 0, 4096, null);
- this.httprequest.downloadFilePtr += len;
- if (len > 0) { this.write(buf.slice(0, len)); } else { fs.closeSync(this.httprequest.downloadFile); this.httprequest.downloadFile = undefined; this.end(); }
- return;
- }
- */
if (this.httprequest.state == 0) {
// Check if this is a relay connection
@@ -1867,8 +1854,7 @@ function createMeshCore(agent) {
this.on('data', onTunnelControlData);
//this.write('MeshCore KVM Hello!1');
- } else if (this.httprequest.protocol == 5)
- {
+ } else if (this.httprequest.protocol == 5) {
//
// Remote Files
//
@@ -2104,12 +2090,36 @@ function createMeshCore(agent) {
if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
if (cmd.path == undefined) break;
var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
+ this.httprequest.uploadFilePath = filepath;
MeshServerLog('Upload: \"' + filepath + '\"', this.httprequest);
try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
this.httprequest.uploadFileid = cmd.reqid;
if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
break;
}
+ case 'uploaddone': {
+ // Indicates that an upload is done
+ if (this.httprequest.uploadFile) {
+ fs.closeSync(this.httprequest.uploadFile);
+ this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
+ delete this.httprequest.uploadFile;
+ delete this.httprequest.uploadFileid;
+ delete this.httprequest.uploadFilePath;
+ }
+ break;
+ }
+ case 'uploadcancel': {
+ // Indicates that an upload is canceled
+ if (this.httprequest.uploadFile) {
+ fs.closeSync(this.httprequest.uploadFile);
+ fs.unlinkSync(this.httprequest.uploadFilePath);
+ this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
+ delete this.httprequest.uploadFile;
+ delete this.httprequest.uploadFileid;
+ delete this.httprequest.uploadFilePath;
+ }
+ break;
+ }
case 'copy': {
// Copy a bunch of files from scpath to dspath
for (var i in cmd.names) {
diff --git a/public/scripts/amt-wsman-0.2.0-min.js b/public/scripts/amt-wsman-0.2.0-min.js
index 293387e7..389c6296 100644
--- a/public/scripts/amt-wsman-0.2.0-min.js
+++ b/public/scripts/amt-wsman-0.2.0-min.js
@@ -1 +1 @@
-var WsmanStackCreateService=function(e,s,r,a,o,t){var p={};function l(e){if(!e)return"";var s=" ";for(var r in e)e.hasOwnProperty(r)&&0===r.indexOf("@")&&(s+=r.substring(1)+'="'+e[r]+'" ');return s}function w(e){if(!e)return"";if("string"==typeof e)return e;if(e.InstanceID)return''+e.InstanceID+"";var s="";for(var r in e)if(e.hasOwnProperty(r)){if(s+='',e[r].ReferenceParameters){s+="",s+=""+e[r].Address+""+e[r].ReferenceParameters.ResourceURI+"";var a=e[r].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(a))for(var o=0;o"+a[o].Value+"";else s+=""+a.Value+"";s+=""}else s+=e[r];s+=""}return s+=""}return p.NextMessageId=1,p.Address="/wsman",p.comm=CreateWsmanComm(e,s,r,a,o,t),p.PerformAjax=function(e,o,s,r,a){null==a&&(a=""),p.comm.PerformAjax('"+e,function(e,s,r){if(200==s){var a=p.ParseWsman(e);a&&null!=a?o(p,a.Header.ResourceURI,a,200,r):o(p,null,{Header:{HttpError:s}},601,r)}else o(p,null,{Header:{HttpError:s}},s,r)},s,r)},p.CancelAllQueries=function(e){p.comm.CancelAllQueries(e)},p.GetNameFromUrl=function(e){var s=e.lastIndexOf("/");return-1==s?e:e.substring(s+1)},p.ExecSubscribe=function(e,s,r,a,o,t,n,l,d,c){var m="",i="";null!=d&&null!=c&&(m="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken"+d+''+c+"",i=''),l=null!=l&&null!=l?""+l+"":"";var u="http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+w(n)+m+''+r+""+i+"PT0.000000S";p.PerformAjax(u+"",a,o,t,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:se="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:m="http://x.com"')},p.ExecUnSubscribe=function(e,s,r,a,o){var t="http://schemas.xmlsoap.org/ws/2004/08/eventing/Unsubscribe"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+w(o)+"";p.PerformAjax(t+"",s,r,a,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing"')},p.ExecPut=function(e,s,r,a,o,t){var n="http://schemas.xmlsoap.org/ws/2004/09/transfer/Put"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S"+w(t)+""+function(e,s){if(!e||null==s)return"";var r=p.GetNameFromUrl(e),a="';for(var o in s)if(s.hasOwnProperty(o)&&0!==o.indexOf("__")&&0!==o.indexOf("@")&&void 0!==s[o]&&null!==s[o]&&"function"!=typeof s[o])if("object"==typeof s[o]&&s[o].ReferenceParameters){a+=""+s[o].Address+""+s[o].ReferenceParameters.ResourceURI+"";var t=s[o].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(t))for(var n=0;n"+t[n].Value+"";else a+=""+t.Value+"";a+=""}else if(Array.isArray(s[o]))for(n=0;n"+s[o][n].toString()+"";else a+=""+s[o].toString()+"";return a+=""}(e,s);p.PerformAjax(n+"",r,a,o)},p.ExecCreate=function(e,s,r,a,o,t){var n=p.GetNameFromUrl(e),l="http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(t)+"';for(var d in s)l+=""+s[d]+"";p.PerformAjax(l+"",r,a,o)},p.ExecCreateXml=function(e,s,r,a,o){var t=p.GetNameFromUrl(e);p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S'+s+"",r,a,o)},p.ExecDelete=function(e,s,r,a,o){var t="http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(s)+"";p.PerformAjax(t,r,a,o)},p.ExecGet=function(e,s,r,a){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S
'+r+"",a,o,t)},p.ExecEnum=function(e,s,r,a){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate"+p.Address+""+e+""+p.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S',s,r,a)},p.ExecPull=function(e,s,r,a,o){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull"+p.Address+""+e+""+p.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S'+s+"99999999",r,a,o)},p.ParseWsman=function(s){try{s.childNodes||(s=function(e){{if(window.DOMParser)return(new DOMParser).parseFromString(e,"text/xml");var s=new ActiveXObject("Microsoft.XMLDOM");return s.async=!1,s.loadXML(e),s}}(s));var e,r={Header:{}},a=s.getElementsByTagName("Header")[0];if(!(a=a||s.getElementsByTagName("a:Header")[0]))return null;for(var o=0;o'+e.InstanceID+"";var s="";for(var r in e)if(e.hasOwnProperty(r)){if(s+='',e[r].ReferenceParameters){s+="",s+=""+e[r].Address+""+e[r].ReferenceParameters.ResourceURI+"";var a=e[r].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(a))for(var o=0;o"+a[o].Value+"";else s+=""+a.Value+"";s+=""}else s+=e[r];s+=""}return s+=""}return p.NextMessageId=1,p.Address="/wsman",p.comm=CreateWsmanComm(e,s,r,a,o,t),p.PerformAjax=function(e,o,s,r,a){null==a&&(a=""),p.comm.PerformAjax('"+e,function(e,s,r){if(200==s){var a=p.ParseWsman(e);a&&null!=a?o(p,a.Header.ResourceURI,a,200,r):o(p,null,{Header:{HttpError:s}},601,r)}else o(p,null,{Header:{HttpError:s}},s,r)},s,r)},p.CancelAllQueries=function(e){p.comm.CancelAllQueries(e)},p.GetNameFromUrl=function(e){var s=e.lastIndexOf("/");return-1==s?e:e.substring(s+1)},p.ExecSubscribe=function(e,s,r,a,o,t,n,l,c,d){var m="",i="";null!=c&&null!=d&&(m="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken"+c+''+d+"",i=''),l=null!=l&&null!=l?""+l+"":"";var u="http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+w(n)+m+''+r+""+i+"PT0.000000S";p.PerformAjax(u+"",a,o,t,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:se="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:m="http://x.com"')},p.ExecUnSubscribe=function(e,s,r,a,o){var t="http://schemas.xmlsoap.org/ws/2004/08/eventing/Unsubscribe"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous"+w(o)+"";p.PerformAjax(t+"",s,r,a,'xmlns:e="http://schemas.xmlsoap.org/ws/2004/08/eventing"')},p.ExecPut=function(e,s,r,a,o,t){var n="http://schemas.xmlsoap.org/ws/2004/09/transfer/Put"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S"+w(t)+""+function(e,s){if(!e||null==s)return"";var r=p.GetNameFromUrl(e),a="';for(var o in s)if(s.hasOwnProperty(o)&&0!==o.indexOf("__")&&0!==o.indexOf("@")&&void 0!==s[o]&&null!==s[o]&&"function"!=typeof s[o])if("object"==typeof s[o]&&s[o].ReferenceParameters){a+=""+s[o].Address+""+s[o].ReferenceParameters.ResourceURI+"";var t=s[o].ReferenceParameters.SelectorSet.Selector;if(Array.isArray(t))for(var n=0;n"+t[n].Value+"";else a+=""+t.Value+"";a+=""}else if(Array.isArray(s[o]))for(n=0;n"+s[o][n].toString()+"";else a+=""+s[o].toString()+"";return a+=""}(e,s);p.PerformAjax(n+"",r,a,o)},p.ExecCreate=function(e,s,r,a,o,t){var n=p.GetNameFromUrl(e),l="http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(t)+"';for(var c in s)l+=""+s[c]+"";p.PerformAjax(l+"",r,a,o)},p.ExecCreateXml=function(e,s,r,a,o){var t=p.GetNameFromUrl(e);p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Create"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60.000S'+s+"",r,a,o)},p.ExecDelete=function(e,s,r,a,o){var t="http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S"+w(s)+"";p.PerformAjax(t,r,a,o)},p.ExecGet=function(e,s,r,a){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/transfer/Get"+p.Address+""+e+""+p.NextMessageId+++"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S'+r+"",a,o,t)},p.ExecEnum=function(e,s,r,a){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate"+p.Address+""+e+""+p.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S',s,r,a)},p.ExecPull=function(e,s,r,a,o){p.PerformAjax("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull"+p.Address+""+e+""+p.NextMessageId+++'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousPT60S'+s+"99999999",r,a,o)},p.ParseWsman=function(s){try{s.childNodes||(s=function(e){{if(window.DOMParser)return(new DOMParser).parseFromString(e,"text/xml");var s=new ActiveXObject("Microsoft.XMLDOM");return s.async=!1,s.loadXML(e),s}}(s));var e,r={Header:{}},a=s.getElementsByTagName("Header")[0];if(!(a=a||s.getElementsByTagName("a:Header")[0]))return null;for(var o=0;o9->446",
+ "default-mobile.handlebars->9->449",
"default.handlebars->27->1439"
]
},
@@ -733,7 +733,7 @@
"fi": "1 tavu",
"xloc": [
"default-mobile.handlebars->9->118",
- "default-mobile.handlebars->9->450",
+ "default-mobile.handlebars->9->453",
"default.handlebars->27->1499"
]
},
@@ -2369,7 +2369,7 @@
"xloc": [
"default-mobile.handlebars->9->226",
"default-mobile.handlebars->9->228",
- "default-mobile.handlebars->9->355",
+ "default-mobile.handlebars->9->358",
"default.handlebars->27->553",
"default.handlebars->27->555",
"default.handlebars->27->930"
@@ -2688,7 +2688,7 @@
"zh-chs": "添加用戶",
"fi": "Lisää Käyttäjä",
"xloc": [
- "default-mobile.handlebars->9->395",
+ "default-mobile.handlebars->9->398",
"default.handlebars->27->648"
]
},
@@ -2757,7 +2757,7 @@
"zh-chs": "将用户添加到设备组",
"fi": "Lisää käyttäjä laiteryhmään",
"xloc": [
- "default-mobile.handlebars->9->424"
+ "default-mobile.handlebars->9->427"
]
},
{
@@ -2996,7 +2996,7 @@
"ru": "Режим управления администратора (ACM)",
"zh-chs": "管理員控制模式(ACM)",
"xloc": [
- "default-mobile.handlebars->9->357",
+ "default-mobile.handlebars->9->360",
"default.handlebars->27->932"
]
},
@@ -3014,7 +3014,7 @@
"ru": "Учетные данные администратора",
"zh-chs": "管理員憑證",
"xloc": [
- "default-mobile.handlebars->9->363",
+ "default-mobile.handlebars->9->366",
"default.handlebars->27->938"
]
},
@@ -3200,7 +3200,7 @@
"zh-chs": "代理控制台",
"fi": "Agentin konsoli",
"xloc": [
- "default-mobile.handlebars->9->430",
+ "default-mobile.handlebars->9->433",
"default.handlebars->27->1422"
]
},
@@ -4178,7 +4178,7 @@
"zh-chs": "建築",
"fi": "Arkkitehtuuri",
"xloc": [
- "default-mobile.handlebars->9->327",
+ "default-mobile.handlebars->9->330",
"default.handlebars->27->892"
]
},
@@ -4215,7 +4215,7 @@
"zh-chs": "您確定要刪除組{0}嗎?刪除設備組還將刪除該組中有關設備的所有信息。",
"fi": "Haluatko varmasti poistaa ryhmän {0}? Laiteryhmän poistaminen poistaa myös kaikki tämän ryhmän laitteiden tiedot.",
"xloc": [
- "default-mobile.handlebars->9->401",
+ "default-mobile.handlebars->9->404",
"default.handlebars->27->1348"
]
},
@@ -4555,7 +4555,7 @@
"ru": "BIOS",
"zh-chs": "的BIOS",
"xloc": [
- "default-mobile.handlebars->9->369",
+ "default-mobile.handlebars->9->372",
"default.handlebars->27->944"
]
},
@@ -5054,7 +5054,7 @@
"ru": "CPU",
"zh-chs": "CPU",
"xloc": [
- "default-mobile.handlebars->9->375",
+ "default-mobile.handlebars->9->378",
"default.handlebars->27->950"
]
},
@@ -5234,8 +5234,8 @@
"zh-chs": "容量",
"fi": "Kapasiteetti",
"xloc": [
- "default-mobile.handlebars->9->383",
- "default-mobile.handlebars->9->385",
+ "default-mobile.handlebars->9->386",
+ "default-mobile.handlebars->9->388",
"default.handlebars->27->958",
"default.handlebars->27->960"
]
@@ -5255,7 +5255,7 @@
"zh-chs": "容量/速度",
"fi": "Kapasiteetti / Nopeus",
"xloc": [
- "default-mobile.handlebars->9->378",
+ "default-mobile.handlebars->9->381",
"default.handlebars->27->953"
]
},
@@ -5585,8 +5585,8 @@
"ru": "Чаты и уведомления",
"zh-chs": "聊天並通知",
"xloc": [
- "default-mobile.handlebars->9->422",
- "default-mobile.handlebars->9->440",
+ "default-mobile.handlebars->9->425",
+ "default-mobile.handlebars->9->443",
"default.handlebars->27->1398",
"default.handlebars->27->1433"
]
@@ -6125,7 +6125,7 @@
"ru": "Режим управления клиентом (CCM)",
"zh-chs": "客戶端控制模式(CCM)",
"xloc": [
- "default-mobile.handlebars->9->356",
+ "default-mobile.handlebars->9->359",
"default.handlebars->27->931"
]
},
@@ -6287,7 +6287,7 @@
"fi": "Varmista",
"xloc": [
"default-mobile.handlebars->9->276",
- "default-mobile.handlebars->9->402",
+ "default-mobile.handlebars->9->405",
"default.handlebars->27->1349",
"default.handlebars->27->1579",
"default.handlebars->27->1657",
@@ -6662,7 +6662,7 @@
"ru": "Подтвердить удаление пользователя {0}?",
"zh-chs": "確認刪除用戶{0}?",
"xloc": [
- "default-mobile.handlebars->9->449"
+ "default-mobile.handlebars->9->452"
]
},
{
@@ -6832,7 +6832,7 @@
"ru": "Подключено сейчас",
"zh-chs": "現在已連接",
"xloc": [
- "default-mobile.handlebars->9->331",
+ "default-mobile.handlebars->9->334",
"default.handlebars->27->896"
]
},
@@ -6868,7 +6868,7 @@
"zh-chs": "正在連線...",
"xloc": [
"default-mobile.handlebars->9->2",
- "default-mobile.handlebars->9->324",
+ "default-mobile.handlebars->9->327",
"default-mobile.handlebars->9->37",
"default.handlebars->27->233",
"default.handlebars->27->236",
@@ -7964,8 +7964,8 @@
"ru": "Удалить группу",
"zh-chs": "刪除群組",
"xloc": [
- "default-mobile.handlebars->9->400",
"default-mobile.handlebars->9->403",
+ "default-mobile.handlebars->9->406",
"default.handlebars->27->1320",
"default.handlebars->27->1350"
]
@@ -8309,9 +8309,9 @@
"default-mobile.handlebars->9->221",
"default-mobile.handlebars->9->222",
"default-mobile.handlebars->9->280",
- "default-mobile.handlebars->9->337",
- "default-mobile.handlebars->9->392",
- "default-mobile.handlebars->9->405",
+ "default-mobile.handlebars->9->340",
+ "default-mobile.handlebars->9->395",
+ "default-mobile.handlebars->9->408",
"default.handlebars->27->1241",
"default.handlebars->27->1269",
"default.handlebars->27->1352",
@@ -8620,7 +8620,7 @@
"ru": "Пользователь группы устройств",
"zh-chs": "設備組用戶",
"xloc": [
- "default-mobile.handlebars->9->447",
+ "default-mobile.handlebars->9->450",
"default.handlebars->27->1440"
]
},
@@ -10106,9 +10106,9 @@
"zh-chs": "編輯設備組",
"fi": "Muokkaa laiteryhmää",
"xloc": [
- "default-mobile.handlebars->9->406",
- "default-mobile.handlebars->9->408",
- "default-mobile.handlebars->9->426",
+ "default-mobile.handlebars->9->409",
+ "default-mobile.handlebars->9->411",
+ "default-mobile.handlebars->9->429",
"default.handlebars->27->1353",
"default.handlebars->27->1383",
"default.handlebars->27->1406",
@@ -10181,7 +10181,7 @@
"ru": "Редактировать примечания устройства",
"zh-chs": "編輯設備說明",
"xloc": [
- "default-mobile.handlebars->9->420",
+ "default-mobile.handlebars->9->423",
"default.handlebars->27->1396"
]
},
@@ -10275,7 +10275,7 @@
"zh-chs": "編輯筆記",
"fi": "Muokkaa muistiinpanoja",
"xloc": [
- "default-mobile.handlebars->9->433",
+ "default-mobile.handlebars->9->436",
"default.handlebars->27->1425"
]
},
@@ -12055,9 +12055,9 @@
"fi": "Täysi Järjestelmänvalvoja",
"xloc": [
"default-mobile.handlebars->9->105",
- "default-mobile.handlebars->9->398",
- "default-mobile.handlebars->9->407",
- "default-mobile.handlebars->9->425",
+ "default-mobile.handlebars->9->401",
+ "default-mobile.handlebars->9->410",
+ "default-mobile.handlebars->9->428",
"default.handlebars->27->1250",
"default.handlebars->27->1382",
"default.handlebars->27->1633"
@@ -12176,7 +12176,7 @@
"nl": "GPU",
"zh-chs": "显卡",
"xloc": [
- "default-mobile.handlebars->9->376",
+ "default-mobile.handlebars->9->379",
"default.handlebars->27->951"
]
},
@@ -13195,8 +13195,8 @@
"ru": "IP: {0}",
"zh-chs": "IP:{0}",
"xloc": [
- "default-mobile.handlebars->9->345",
- "default-mobile.handlebars->9->349",
+ "default-mobile.handlebars->9->348",
+ "default-mobile.handlebars->9->352",
"default.handlebars->27->910",
"default.handlebars->27->920",
"default.handlebars->27->924"
@@ -13216,8 +13216,8 @@
"ru": "IP: {0}, маска: {1}, шлюз: {2}",
"zh-chs": "IP:{0},掩碼:{1},網關:{2}",
"xloc": [
- "default-mobile.handlebars->9->343",
- "default-mobile.handlebars->9->347",
+ "default-mobile.handlebars->9->346",
+ "default-mobile.handlebars->9->350",
"default.handlebars->27->908",
"default.handlebars->27->918",
"default.handlebars->27->922"
@@ -13237,8 +13237,8 @@
"ru": "Уровень IPv4",
"zh-chs": "IPv4層",
"xloc": [
- "default-mobile.handlebars->9->342",
- "default-mobile.handlebars->9->344",
+ "default-mobile.handlebars->9->345",
+ "default-mobile.handlebars->9->347",
"default.handlebars->27->907",
"default.handlebars->27->909",
"default.handlebars->27->917",
@@ -13306,8 +13306,8 @@
"nl": "IPv6 Layer",
"es": "Capa IPv6",
"xloc": [
- "default-mobile.handlebars->9->346",
- "default-mobile.handlebars->9->348",
+ "default-mobile.handlebars->9->349",
+ "default-mobile.handlebars->9->351",
"default.handlebars->27->921",
"default.handlebars->27->923"
]
@@ -13385,7 +13385,7 @@
"ru": "Идентификатор",
"zh-chs": "識別碼",
"xloc": [
- "default-mobile.handlebars->9->374",
+ "default-mobile.handlebars->9->377",
"default.handlebars->27->949"
]
},
@@ -14171,7 +14171,7 @@
"ru": "Только Intel® AMT, без агента",
"zh-chs": "僅限英特爾®AMT,無代理",
"xloc": [
- "default-mobile.handlebars->9->389",
+ "default-mobile.handlebars->9->392",
"default.handlebars->27->1240",
"default.handlebars->27->1266"
]
@@ -14207,7 +14207,7 @@
"ru": "Intel® Active Management Technology (Intel® AMT)",
"zh-chs": "英特爾®主動管理技術(英特爾®AMT)",
"xloc": [
- "default-mobile.handlebars->9->366",
+ "default-mobile.handlebars->9->369",
"default.handlebars->27->941"
]
},
@@ -15069,7 +15069,7 @@
"ru": "Известный",
"zh-chs": "已知的",
"xloc": [
- "default-mobile.handlebars->9->365",
+ "default-mobile.handlebars->9->368",
"default.handlebars->27->940"
]
},
@@ -15417,9 +15417,9 @@
"ru": "Последний адрес агента",
"zh-chs": "最後代理商地址",
"xloc": [
- "default-mobile.handlebars->9->333",
- "default-mobile.handlebars->9->334",
- "default-mobile.handlebars->9->335",
+ "default-mobile.handlebars->9->336",
+ "default-mobile.handlebars->9->337",
+ "default-mobile.handlebars->9->338",
"default.handlebars->27->69",
"default.handlebars->27->71",
"default.handlebars->27->73",
@@ -15442,8 +15442,8 @@
"ru": "Последнее подключение агента",
"zh-chs": "上次代理連接",
"xloc": [
- "default-mobile.handlebars->9->330",
- "default-mobile.handlebars->9->332",
+ "default-mobile.handlebars->9->333",
+ "default-mobile.handlebars->9->335",
"default.handlebars->27->68",
"default.handlebars->27->895",
"default.handlebars->27->897"
@@ -15749,7 +15749,7 @@
"ru": "Ограниченный ввод",
"zh-chs": "有限輸入",
"xloc": [
- "default-mobile.handlebars->9->438",
+ "default-mobile.handlebars->9->441",
"default.handlebars->27->1431",
"default.handlebars->27->661",
"default.handlebars->27->680"
@@ -15769,7 +15769,7 @@
"ru": "Ограничить элементы ввода",
"zh-chs": "僅限於輸入",
"xloc": [
- "default-mobile.handlebars->9->413",
+ "default-mobile.handlebars->9->416",
"default.handlebars->27->1388"
]
},
@@ -16542,8 +16542,8 @@
"ru": "MAC-уровень",
"zh-chs": "MAC層",
"xloc": [
- "default-mobile.handlebars->9->338",
- "default-mobile.handlebars->9->340",
+ "default-mobile.handlebars->9->341",
+ "default-mobile.handlebars->9->343",
"default.handlebars->27->903",
"default.handlebars->27->905",
"default.handlebars->27->913",
@@ -16582,7 +16582,7 @@
"ru": "MAC: {0}",
"zh-chs": "MAC:{0}",
"xloc": [
- "default-mobile.handlebars->9->341",
+ "default-mobile.handlebars->9->344",
"default.handlebars->27->906",
"default.handlebars->27->916"
]
@@ -16601,7 +16601,7 @@
"ru": "MAC: {0}, шлюз: {1}",
"zh-chs": "MAC:{0},網關:{1}",
"xloc": [
- "default-mobile.handlebars->9->339",
+ "default-mobile.handlebars->9->342",
"default.handlebars->27->904",
"default.handlebars->27->914"
]
@@ -16925,8 +16925,8 @@
"zh-chs": "管理設備組計算機",
"fi": "Hallitse laiteryhmän tietokoneita",
"xloc": [
- "default-mobile.handlebars->9->410",
- "default-mobile.handlebars->9->428",
+ "default-mobile.handlebars->9->413",
+ "default-mobile.handlebars->9->431",
"default.handlebars->27->1385",
"default.handlebars->27->1420"
]
@@ -16946,8 +16946,8 @@
"zh-chs": "管理設備組用戶",
"fi": "Hallitse laiteryhmän käyttäjiä",
"xloc": [
- "default-mobile.handlebars->9->409",
- "default-mobile.handlebars->9->427",
+ "default-mobile.handlebars->9->412",
+ "default-mobile.handlebars->9->430",
"default.handlebars->27->1384",
"default.handlebars->27->1419"
]
@@ -17157,7 +17157,7 @@
"ru": "Управляется с помощью программного агента",
"zh-chs": "使用軟件代理進行管理",
"xloc": [
- "default-mobile.handlebars->9->390",
+ "default-mobile.handlebars->9->393",
"default.handlebars->27->1267"
]
},
@@ -17350,7 +17350,7 @@
"ru": "ОЗУ",
"zh-chs": "記憶",
"xloc": [
- "default-mobile.handlebars->9->381",
+ "default-mobile.handlebars->9->384",
"default.handlebars->27->1901",
"default.handlebars->27->956",
"default.handlebars->container->column_l->p40->3->1->p40type->3"
@@ -17371,8 +17371,8 @@
"zh-chs": "網格代理",
"xloc": [
"default-mobile.handlebars->9->250",
- "default-mobile.handlebars->9->329",
- "default-mobile.handlebars->9->336",
+ "default-mobile.handlebars->9->332",
+ "default-mobile.handlebars->9->339",
"default.handlebars->27->378",
"default.handlebars->27->382",
"default.handlebars->27->391",
@@ -17399,7 +17399,7 @@
"ru": "Консоль Mesh Agent",
"zh-chs": "網格代理控制台",
"xloc": [
- "default-mobile.handlebars->9->417",
+ "default-mobile.handlebars->9->420",
"default.handlebars->27->1393"
]
},
@@ -17973,7 +17973,7 @@
"nl": "Model",
"zh-chs": "模型",
"xloc": [
- "default-mobile.handlebars->9->382",
+ "default-mobile.handlebars->9->385",
"default.handlebars->27->957"
]
},
@@ -18043,7 +18043,7 @@
"ru": "Материнская плата",
"zh-chs": "母板",
"xloc": [
- "default-mobile.handlebars->9->377",
+ "default-mobile.handlebars->9->380",
"default.handlebars->27->952"
]
},
@@ -18369,10 +18369,10 @@
"fi": "Nimi",
"xloc": [
"default-mobile.handlebars->9->215",
- "default-mobile.handlebars->9->325",
- "default-mobile.handlebars->9->371",
- "default-mobile.handlebars->9->391",
- "default-mobile.handlebars->9->404",
+ "default-mobile.handlebars->9->328",
+ "default-mobile.handlebars->9->374",
+ "default-mobile.handlebars->9->394",
+ "default-mobile.handlebars->9->407",
"default-mobile.handlebars->9->97",
"default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea3->deskarea3x->DeskTools->5->1->1",
"default.handlebars->27->1237",
@@ -18527,7 +18527,7 @@
"ru": "сетей",
"zh-chs": "聯網",
"xloc": [
- "default-mobile.handlebars->9->350",
+ "default-mobile.handlebars->9->353",
"default.handlebars->27->911",
"default.handlebars->27->925"
]
@@ -18807,7 +18807,7 @@
"ru": "Нет доступа к файлам",
"zh-chs": "沒有文件訪問",
"xloc": [
- "default-mobile.handlebars->9->415",
+ "default-mobile.handlebars->9->418",
"default.handlebars->27->1391"
]
},
@@ -18826,7 +18826,7 @@
"zh-chs": "沒有文件",
"fi": "Ei tiedostoja",
"xloc": [
- "default-mobile.handlebars->9->436",
+ "default-mobile.handlebars->9->439",
"default.handlebars->27->1429",
"default.handlebars->27->659",
"default.handlebars->27->678"
@@ -18863,8 +18863,8 @@
"ru": "Нет Intel® AMT",
"zh-chs": "沒有英特爾®AMT",
"xloc": [
- "default-mobile.handlebars->9->416",
- "default-mobile.handlebars->9->437",
+ "default-mobile.handlebars->9->419",
+ "default-mobile.handlebars->9->440",
"default.handlebars->27->1392",
"default.handlebars->27->1430"
]
@@ -18989,8 +18989,8 @@
"zh-chs": "沒有權利",
"xloc": [
"default-mobile.handlebars->9->106",
- "default-mobile.handlebars->9->399",
- "default-mobile.handlebars->9->442",
+ "default-mobile.handlebars->9->402",
+ "default-mobile.handlebars->9->445",
"default.handlebars->27->1251",
"default.handlebars->27->1435",
"default.handlebars->27->671",
@@ -19030,7 +19030,7 @@
"ru": "Нет терминала",
"zh-chs": "沒有終端",
"xloc": [
- "default-mobile.handlebars->9->435",
+ "default-mobile.handlebars->9->438",
"default.handlebars->27->1428",
"default.handlebars->27->658",
"default.handlebars->27->677"
@@ -19050,7 +19050,7 @@
"ru": "Нет доступа к терминалу",
"zh-chs": "沒有終端訪問",
"xloc": [
- "default-mobile.handlebars->9->414",
+ "default-mobile.handlebars->9->417",
"default.handlebars->27->1390"
]
},
@@ -19291,7 +19291,7 @@
"ru": "Информации об этом устройстве нет",
"zh-chs": "沒有此設備的信息。",
"xloc": [
- "default-mobile.handlebars->9->387",
+ "default-mobile.handlebars->9->390",
"default.handlebars->27->962"
]
},
@@ -19495,7 +19495,7 @@
"default-mobile.handlebars->9->220",
"default-mobile.handlebars->9->245",
"default-mobile.handlebars->9->297",
- "default-mobile.handlebars->9->393",
+ "default-mobile.handlebars->9->396",
"default.handlebars->27->1263",
"default.handlebars->27->1270",
"default.handlebars->27->1274",
@@ -19607,7 +19607,7 @@
"zh-chs": "未激活(輸入)",
"xloc": [
"default-mobile.handlebars->9->225",
- "default-mobile.handlebars->9->354",
+ "default-mobile.handlebars->9->357",
"default.handlebars->27->552",
"default.handlebars->27->929"
]
@@ -19627,7 +19627,7 @@
"zh-chs": "未激活(預)",
"xloc": [
"default-mobile.handlebars->9->224",
- "default-mobile.handlebars->9->353",
+ "default-mobile.handlebars->9->356",
"default.handlebars->27->551",
"default.handlebars->27->928"
]
@@ -19664,7 +19664,7 @@
"ru": "Неизвестный",
"zh-chs": "未知",
"xloc": [
- "default-mobile.handlebars->9->364",
+ "default-mobile.handlebars->9->367",
"default.handlebars->27->939"
]
},
@@ -20198,7 +20198,7 @@
"ru": "Операционная система",
"zh-chs": "操作系統",
"xloc": [
- "default-mobile.handlebars->9->328",
+ "default-mobile.handlebars->9->331",
"default.handlebars->27->332",
"default.handlebars->27->365",
"default.handlebars->27->575",
@@ -20381,7 +20381,7 @@
"ru": "Part Number",
"zh-chs": "零件號",
"xloc": [
- "default-mobile.handlebars->9->380",
+ "default-mobile.handlebars->9->383",
"default.handlebars->27->955"
]
},
@@ -20445,7 +20445,7 @@
"zh-chs": "部分權利",
"xloc": [
"default-mobile.handlebars->9->104",
- "default-mobile.handlebars->9->397",
+ "default-mobile.handlebars->9->400",
"default.handlebars->27->1249"
]
},
@@ -20918,7 +20918,7 @@
"zh-chs": "權限",
"fi": "Käyttöoikeudet",
"xloc": [
- "default-mobile.handlebars->9->445",
+ "default-mobile.handlebars->9->448",
"default.handlebars->27->1438",
"default.handlebars->27->1545"
]
@@ -21618,7 +21618,7 @@
"ru": "Предоставление государства",
"zh-chs": "供應國",
"xloc": [
- "default-mobile.handlebars->9->358",
+ "default-mobile.handlebars->9->361",
"default.handlebars->27->933"
]
},
@@ -22302,8 +22302,8 @@
"zh-chs": "遙控",
"fi": "Etähallinta",
"xloc": [
- "default-mobile.handlebars->9->411",
- "default-mobile.handlebars->9->429",
+ "default-mobile.handlebars->9->414",
+ "default-mobile.handlebars->9->432",
"default.handlebars->27->1386",
"default.handlebars->27->1421"
]
@@ -22378,7 +22378,7 @@
"ru": "Удаленный пользователь Mesh",
"zh-chs": "遠程網狀用戶",
"xloc": [
- "default-mobile.handlebars->9->448"
+ "default-mobile.handlebars->9->451"
]
},
{
@@ -22410,8 +22410,8 @@
"ru": "Только просмотр экрана без ввода",
"zh-chs": "僅遠程查看",
"xloc": [
- "default-mobile.handlebars->9->412",
- "default-mobile.handlebars->9->434",
+ "default-mobile.handlebars->9->415",
+ "default-mobile.handlebars->9->437",
"default.handlebars->27->1387",
"default.handlebars->27->1426"
]
@@ -23796,7 +23796,7 @@
"ru": "Защищено с помощью TLS",
"zh-chs": "使用TLS保護",
"xloc": [
- "default-mobile.handlebars->9->361",
+ "default-mobile.handlebars->9->364",
"default.handlebars->27->936"
]
},
@@ -23816,7 +23816,7 @@
"fi": "Turvallisuus",
"xloc": [
"default-mobile.handlebars->9->270",
- "default-mobile.handlebars->9->360",
+ "default-mobile.handlebars->9->363",
"default.handlebars->27->1766",
"default.handlebars->27->286",
"default.handlebars->27->732",
@@ -24042,7 +24042,7 @@
"ru": "Только собственные события",
"zh-chs": "僅自我事件",
"xloc": [
- "default-mobile.handlebars->9->439",
+ "default-mobile.handlebars->9->442",
"default.handlebars->27->1432"
]
},
@@ -24328,7 +24328,7 @@
"ru": "Серийный номер",
"zh-chs": "序列號",
"xloc": [
- "default-mobile.handlebars->9->372",
+ "default-mobile.handlebars->9->375",
"default.handlebars->27->947"
]
},
@@ -24397,8 +24397,8 @@
"ru": "Серверные файлы",
"zh-chs": "服務器文件",
"xloc": [
- "default-mobile.handlebars->9->418",
- "default-mobile.handlebars->9->431",
+ "default-mobile.handlebars->9->421",
+ "default-mobile.handlebars->9->434",
"default.handlebars->27->1394",
"default.handlebars->27->1423",
"default.handlebars->27->1631",
@@ -25048,7 +25048,7 @@
"ru": "Показывать только собственные события",
"zh-chs": "只顯示自己的事件",
"xloc": [
- "default-mobile.handlebars->9->421",
+ "default-mobile.handlebars->9->424",
"default.handlebars->27->1397"
]
},
@@ -26274,7 +26274,7 @@
"nl": "Opslag",
"zh-chs": "存储",
"xloc": [
- "default-mobile.handlebars->9->386",
+ "default-mobile.handlebars->9->389",
"default.handlebars->27->961"
]
},
@@ -26637,7 +26637,7 @@
"ru": "TLS не настроен",
"zh-chs": "未設置TLS",
"xloc": [
- "default-mobile.handlebars->9->362",
+ "default-mobile.handlebars->9->365",
"default.handlebars->27->937"
]
},
@@ -27938,7 +27938,7 @@
"ru": "Удаленный ввод",
"zh-chs": "類型",
"xloc": [
- "default-mobile.handlebars->9->394",
+ "default-mobile.handlebars->9->397",
"default-mobile.handlebars->9->98",
"default.handlebars->27->1238",
"default.handlebars->27->1271",
@@ -28201,7 +28201,7 @@
"ru": "Удаление",
"zh-chs": "卸載",
"xloc": [
- "default-mobile.handlebars->9->441",
+ "default-mobile.handlebars->9->444",
"default.handlebars->27->1434",
"default.handlebars->27->670",
"default.handlebars->27->689"
@@ -28221,7 +28221,7 @@
"ru": "Удаление агента",
"zh-chs": "卸載代理",
"xloc": [
- "default-mobile.handlebars->9->423",
+ "default-mobile.handlebars->9->426",
"default.handlebars->27->1399",
"default.handlebars->27->444",
"default.handlebars->27->720"
@@ -28261,8 +28261,8 @@
"default-mobile.handlebars->9->204",
"default-mobile.handlebars->9->34",
"default-mobile.handlebars->9->35",
- "default-mobile.handlebars->9->352",
- "default-mobile.handlebars->9->359",
+ "default-mobile.handlebars->9->355",
+ "default-mobile.handlebars->9->362",
"default-mobile.handlebars->9->6",
"default.handlebars->27->107",
"default.handlebars->27->108",
@@ -28296,7 +28296,7 @@
"ru": "Неизвестно #{0}",
"zh-chs": "未知#{0}",
"xloc": [
- "default-mobile.handlebars->9->388",
+ "default-mobile.handlebars->9->391",
"default.handlebars->27->1265"
]
},
@@ -28534,6 +28534,7 @@
"default-mobile.handlebars->9->126",
"default-mobile.handlebars->9->305",
"default-mobile.handlebars->9->323",
+ "default-mobile.handlebars->9->326",
"default.handlebars->27->1507",
"default.handlebars->27->1515",
"default.handlebars->27->860",
@@ -28624,6 +28625,7 @@
"ru": "Загрузка перезапишет 1 файл. Продолжить?",
"zh-chs": "上傳將覆蓋1個文件。繼續?",
"xloc": [
+ "default-mobile.handlebars->9->324",
"default.handlebars->27->1516",
"default.handlebars->27->884"
]
@@ -28642,6 +28644,7 @@
"ru": "Загрузка перезапишет {0} файлов. Продолжить?",
"zh-chs": "上傳將覆蓋{0}個文件。繼續?",
"xloc": [
+ "default-mobile.handlebars->9->325",
"default.handlebars->27->1517",
"default.handlebars->27->885"
]
@@ -28838,7 +28841,7 @@
"ru": "Полномочия пользователя",
"zh-chs": "用戶授權",
"xloc": [
- "default-mobile.handlebars->9->396",
+ "default-mobile.handlebars->9->399",
"default.handlebars->27->1317",
"default.handlebars->27->650"
]
@@ -28925,7 +28928,7 @@
"nl": "Gebruikers ID",
"es": "ID de usuario",
"xloc": [
- "default-mobile.handlebars->9->444"
+ "default-mobile.handlebars->9->447"
]
},
{
@@ -28987,7 +28990,7 @@
"ru": "Имя пользователя",
"zh-chs": "用戶名",
"xloc": [
- "default-mobile.handlebars->9->443",
+ "default-mobile.handlebars->9->446",
"default.handlebars->27->1436"
]
},
@@ -29327,8 +29330,8 @@
"ru": "Вендор",
"zh-chs": "供應商",
"xloc": [
- "default-mobile.handlebars->9->367",
"default-mobile.handlebars->9->370",
+ "default-mobile.handlebars->9->373",
"default.handlebars->27->942",
"default.handlebars->27->945"
]
@@ -29442,10 +29445,10 @@
"zh-chs": "版",
"fi": "Versio",
"xloc": [
- "default-mobile.handlebars->9->326",
- "default-mobile.handlebars->9->351",
- "default-mobile.handlebars->9->368",
- "default-mobile.handlebars->9->373",
+ "default-mobile.handlebars->9->329",
+ "default-mobile.handlebars->9->354",
+ "default-mobile.handlebars->9->371",
+ "default-mobile.handlebars->9->376",
"default.handlebars->27->891",
"default.handlebars->27->926",
"default.handlebars->27->943",
@@ -29688,8 +29691,8 @@
"ru": "Разбудить устройства",
"zh-chs": "喚醒設備",
"xloc": [
- "default-mobile.handlebars->9->419",
- "default-mobile.handlebars->9->432",
+ "default-mobile.handlebars->9->422",
+ "default-mobile.handlebars->9->435",
"default.handlebars->27->1395",
"default.handlebars->27->1424"
]
@@ -32016,7 +32019,7 @@
"ru": "{0} Mб",
"zh-chs": "{0} Mb",
"xloc": [
- "default-mobile.handlebars->9->384",
+ "default-mobile.handlebars->9->387",
"default.handlebars->27->1491",
"default.handlebars->27->959"
]
@@ -32035,7 +32038,7 @@
"ru": "{0} Мб, {1} Мгц",
"zh-chs": "{0} Mb,{1} Mhz",
"xloc": [
- "default-mobile.handlebars->9->379",
+ "default-mobile.handlebars->9->382",
"default.handlebars->27->954"
]
},
diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars
index b62230a6..4a67ac2a 100644
--- a/views/default-mobile.handlebars
+++ b/views/default-mobile.handlebars
@@ -3304,27 +3304,31 @@
var p13filetreelocation = [];
function p13gotFiles(data) {
- setSessionActivity();
- //console.log('p13gotFiles', data);
- if ((data.length > 0) && (data.charCodeAt(0) != 123)) { p13gotDownloadBinaryData(data); return; }
+ if ((data.length > 0) && (data.charCodeAt(0) != 123)) { p13gotDownloadBinaryData(data); return; } // This is ok because 4 first bytes is a control value.
//console.log('p13gotFiles', data);
data = JSON.parse(decode_utf8(data));
if (data.action == 'download') { p13gotDownloadCommand(data); return; }
- data.path = data.path.replace(/\//g, '\\');
- if ((p13filetree != null) && (data.path == p13filetree.path)) {
- // This is an update to the same folder
- var checkedNames = p13getCheckedNames();
- p13filetree = data;
- p13updateFiles(checkedNames);
- } else {
- // Make both paths use the same seperator not start with /
- var x1 = data.path.replace(/\//g, '\\'), x2 = p13targetpath.replace(/\//g, '\\');
- while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
- while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
- if ((x1 == x2) || ((data.path == '\\') && (p13targetpath == ''))) {
- // This is a different folder
+
+ // Process file upload commands
+ if ((data.action != null) && (data.action.startsWith('upload'))) { p13gotUploadData(data); return; }
+
+ if (data.path != null) {
+ data.path = data.path.replace(/\//g, '\\');
+ if ((p13filetree != null) && (data.path == p13filetree.path)) {
+ // This is an update to the same folder
+ var checkedNames = p13getCheckedNames();
p13filetree = data;
- p13updateFiles();
+ p13updateFiles(checkedNames);
+ } else {
+ // Make both paths use the same seperator not start with /
+ var x1 = data.path.replace(/\//g, '\\'), x2 = p13targetpath.replace(/\//g, '\\');
+ while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
+ while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
+ if ((x1 == x2) || ((data.path == '\\') && (p13targetpath == ''))) {
+ // This is a different folder
+ p13filetree = data;
+ p13updateFiles();
+ }
}
}
}
@@ -3614,35 +3618,35 @@
var uploadFile;
function p13doUploadFiles(files) {
if (xxdialogMode) return;
+
+ // Check if we are going to overwrite any files
+ var winAgent = ((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
+ var targetFiles = [], overWriteCount = 0;
+ for (var i in p13filetree.dir) { if (winAgent) { targetFiles.push(p13filetree.dir[i].n.toLowerCase()); } else { targetFiles.push(p13filetree.dir[i].n); } }
+ for (var i = 0; i < files.length; i++) {
+ if (winAgent) {
+ if (targetFiles.indexOf(files[i].name.toLowerCase()) >= 0) { overWriteCount++; }
+ } else {
+ if (targetFiles.indexOf(files[i].name) >= 0) { overWriteCount++; }
+ }
+ }
+
+ if (overWriteCount == 0) {
+ // If no overwrite, go ahead with upload
+ p13uploadFileContinue(1, files);
+ } else {
+ // Otherwise, prompt for confirmation
+ setDialogMode(2, "Upload File", 3, p13uploadFileContinue, format((overWriteCount == 1) ? "Upload will overwrite 1 file. Continue?" : "Upload will overwrite {0} files. Continue?", overWriteCount), files);
+ }
+ }
+
+ function p13uploadFileContinue(b, files) {
uploadFile = {};
uploadFile.xpath = p13filetreelocation.join('/');
uploadFile.xfiles = files;
uploadFile.xfilePtr = -1;
setDialogMode(2, "Upload File", 10, p13uploadFileCancel, '' + "Connecting..." + '
');
- p13uploadReconnect();
- }
-
- function onFileUploadStateChange(xdownloadFile, state) {
- switch (state) {
- case 0:
- p13folderup(9999);
- break;
- case 3:
- p13uploadNextFile();
- break;
- default:
- console.log('Unknown onFileUploadStateChange state', state);
- break;
- }
- }
-
- // Connect again
- function p13uploadReconnect() {
- uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
- uploadFile.ws.attemptWebRTC = false;
- uploadFile.ws.ctrlMsgAllowed = false;
- uploadFile.ws.onStateChanged = onFileUploadStateChange;
- uploadFile.ws.Start(filesNode._id);
+ p13uploadNextFile();
}
// Push the next file
@@ -3654,61 +3658,69 @@
QH('p13dfileName', file.name);
Q('d2progressBar').max = file.size;
Q('d2progressBar').value = 0;
-
- uploadFile.xreader = new FileReader();
- uploadFile.xreader.onload = function () {
- uploadFile.xdata = uploadFile.xreader.result;
- uploadFile.ws.sendText({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength });
- };
- uploadFile.xreader.readAsArrayBuffer(file);
+ if (file.xdata == null) {
+ // Load the data
+ uploadFile.xreader = new FileReader();
+ uploadFile.xreader.onload = function () {
+ uploadFile.xdata = uploadFile.xreader.result;
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
+ };
+ uploadFile.xreader.readAsArrayBuffer(file);
+ } else {
+ // Data already loaded
+ uploadFile.xdata = file.xdata;
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
+ }
} else {
- p13uploadFileCancel();
+ p13uploadFileTransferDone();
}
}
// Used to cancel the entire transfer.
function p13uploadFileCancel(button, tag) {
- if (uploadFile != null) {
- if (uploadFile.ws != null) {
- uploadFile.ws.Stop();
- uploadFile.ws = null;
- }
- uploadFile = null;
- }
- setDialogMode(0); // Close any dialog boxes if present
+ if (uploadFile != null) { files.sendText(JSON.stringify({ action: 'uploadcancel', reqid: uploadFile.xfilePtr })); uploadFile = null; }
+ p13uploadFileTransferDone();
+ }
+
+ // Used to cancel the entire transfer.
+ function p13uploadFileTransferDone() {
+ uploadFile = null; // No more files to upload, clean up.
+ setDialogMode(0); // Close the dialog box
+ p13folderup(9999); // Refresh the current folder
}
// Receive upload ack from the mesh agent, use this to keep sending more data
- function p13gotUploadData(data) {
- var cmd = JSON.parse(data);
+ function p13gotUploadData(cmd) {
if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
-
- if (cmd.action == 'uploadstart') {
- p13uploadNextPart(false);
- for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } // Send 8 more blocks of 4 k to full the websocket.
- } else if (cmd.action == 'uploadack') {
- p13uploadNextPart(false);
- } else if (cmd.action == 'uploaderror') {
- p13uploadFileCancel();
+ switch (cmd.action) {
+ case 'uploadstart': { p13uploadNextPart(false); for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } break; } // Send 8 more blocks of 16k to fill the websocket.
+ case 'uploadack': { p13uploadNextPart(false); break; }
+ case 'uploaddone': { if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadNextFile(); } else { p13uploadFileTransferDone(); } break; }
+ case 'uploaderror': { p13uploadFileCancel(); break; }
}
}
// Push the next part of the file into the websocket. If dataPriming is true, push more data only if it's not the last block of the file.
function p13uploadNextPart(dataPriming) {
- var data = uploadFile.xdata;
- var start = uploadFile.xptr;
- var end = uploadFile.xptr + 4096;
- if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
- if (start == data.byteLength) {
- if (uploadFile.ws != null) { uploadFile.ws.Stop(); uploadFile.ws = null; }
- if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadReconnect(); } else { p13uploadFileCancel(); }
+ var data = uploadFile.xdata, start = uploadFile.xptr;
+ if (start >= data.byteLength) {
+ files.sendText(JSON.stringify({ action: 'uploaddone', reqid: uploadFile.xfilePtr }));
} else {
- var datapart = data.slice(start, end);
- uploadFile.ws.send(datapart);
+ var end = uploadFile.xptr + 16384;
+ if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
+ var dataslice = new Uint8Array(data.slice(start, end))
+ if ((dataslice[0] == 123) || (dataslice[0] == 0)) {
+ var datapart = new Uint8Array(end - start + 1);
+ datapart.set(dataslice, 1); // Add a zero char at the start of the send, this will indicate that it's not a JSON command.
+ files.send(datapart);
+ } else {
+ files.send(dataslice); // The data does not start with 0 or 123 "{" so it can't be confused for JSON.
+ }
uploadFile.xptr = end;
Q('d2progressBar').value = end;
}
}
+
//
// DEVICE DETAILS
//
diff --git a/views/default.handlebars b/views/default.handlebars
index 2f7007bd..9f6db7e6 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -7713,21 +7713,27 @@
//console.log('p13gotFiles', data);
data = JSON.parse(decode_utf8(data));
if (data.action == 'download') { p13gotDownloadCommand(data); return; }
- data.path = data.path.replace(/\//g, '\\');
- if ((p13filetree != null) && (data.path == p13filetree.path)) {
- // This is an update to the same folder
- var checkedNames = p13getCheckedNames();
- p13filetree = data;
- p13updateFiles(checkedNames);
- } else {
- // Make both paths use the same seperator not start with /
- var x1 = data.path.replace(/\//g, '\\'), x2 = p13targetpath.replace(/\//g, '\\');
- while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
- while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
- if ((x1 == x2) || ((data.path == '\\') && (p13targetpath == ''))) {
- // This is a different folder
+
+ // Process file upload commands
+ if ((data.action != null) && (data.action.startsWith('upload'))) { p13gotUploadData(data); return; }
+
+ if (data.path != null) {
+ data.path = data.path.replace(/\//g, '\\');
+ if ((p13filetree != null) && (data.path == p13filetree.path)) {
+ // This is an update to the same folder
+ var checkedNames = p13getCheckedNames();
p13filetree = data;
- p13updateFiles();
+ p13updateFiles(checkedNames);
+ } else {
+ // Make both paths use the same seperator not start with /
+ var x1 = data.path.replace(/\//g, '\\'), x2 = p13targetpath.replace(/\//g, '\\');
+ while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
+ while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
+ if ((x1 == x2) || ((data.path == '\\') && (p13targetpath == ''))) {
+ // This is a different folder
+ p13filetree = data;
+ p13updateFiles();
+ }
}
}
}
@@ -8020,68 +8026,6 @@
p13uploadFileContinue(1, [{ name: tag, size: data.byteLength, type: 'text/plain', xdata: data }]);
}
- /*
- var downloadFile; // Global state for file download
-
- // Called by the html page to start a download, arguments are: path, file name and file size.
- function p13downloadfile(x, y, z) {
- if (xxdialogMode) return;
- downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl); // Create our websocket file transport
- downloadFile.ctrlMsgAllowed = false;
- downloadFile.onStateChanged = onFileDownloadStateChange;
- downloadFile.xpath = decodeURIComponent(x);
- downloadFile.xfile = decodeURIComponent(y);
- downloadFile.xsize = z;
- downloadFile.xtsize = 0;
- downloadFile.xstate = 0;
- downloadFile.Start(filesNode._id);
- setDialogMode(2, "Download File", 10, p13downloadFileCancel, '' + downloadFile.xfile + '
');
- }
-
- // Called by the html page to cancel the download
- function p13downloadFileCancel(button, tag) {
- //console.log('p13downloadFileCancel');
- downloadFile.Stop();
- delete downloadFile;
- downloadFile = null;
- }
-
- // Called by the file transport to indicate when the transport connection state has changed
- function onFileDownloadStateChange(xdownloadFile, state) {
- switch (state) {
- case 0: // Transport as disconnected. If this is not part of an abort, we need to save the file
- setDialogMode(0); // Close any dialog boxes if present
- if ((downloadFile != null) && (downloadFile.xstate == 1)) { saveAs(data2blob(downloadFile.xdata), downloadFile.xfile); } // Save the file
- break;
- case 3: // Transport as connected, send a command to indicate we want to start a file download
- downloadFile.send(JSON.stringify({ action: 'download', reqid: 1, path: downloadFile.xpath }));
- break;
- default:
- console.log('Unknown onFileDownloadStateChange state', state);
- break;
- }
- }
-
- // Called by the transport when data is received
- function p13gotDownloadData(data) {
- if (downloadFile.xstate == 0) { // If state is 0, this is a command confirming if the file will be transfered.
- var cmd = JSON.parse(data);
- if (cmd.action == 'downloadstart') { // Yes, the file is about to start
- downloadFile.xstate = 1; // Switch to state 1, we will start receiving the file data
- downloadFile.xdata = ''; // Start with empty data
- downloadFile.send('a'); // Send the first ACK
- } else if (cmd.action == 'downloaderror') { // Problem opening this file, cancel
- p13downloadFileCancel();
- }
- } else { // We are in the process of receiving the file
- downloadFile.xtsize += (data.length); // Add to the total bytes received
- downloadFile.xdata += data; // Append the data
- Q('d2progressBar').value = downloadFile.xtsize; // Change the progress bar
- downloadFile.send('a'); // Send the ACK
- }
- }
- */
-
//
// FILES UPLOAD
//
@@ -8117,28 +8061,7 @@
uploadFile.xfiles = files;
uploadFile.xfilePtr = -1;
setDialogMode(2, "Upload File", 10, p13uploadFileCancel, '' + "Connecting..." + '
');
- p13uploadReconnect();
- }
-
- function onFileUploadStateChange(xdownloadFile, state) {
- switch (state) {
- case 0:
- setTimeout(function () { p13folderup(9999); }, 200); // Delay the file refresh
- break;
- case 3:
- p13uploadNextFile();
- break;
- default:
- break;
- }
- }
-
- // Connect again
- function p13uploadReconnect() {
- uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
- uploadFile.ws.attemptWebRTC = false;
- uploadFile.ws.onStateChanged = onFileUploadStateChange;
- uploadFile.ws.Start(filesNode._id);
+ p13uploadNextFile();
}
// Push the next file
@@ -8150,66 +8073,64 @@
QH('p13dfileName', file.name);
Q('d2progressBar').max = file.size;
Q('d2progressBar').value = 0;
-
if (file.xdata == null) {
// Load the data
uploadFile.xreader = new FileReader();
uploadFile.xreader.onload = function () {
uploadFile.xdata = uploadFile.xreader.result;
- uploadFile.ws.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
};
uploadFile.xreader.readAsArrayBuffer(file);
} else {
// Data already loaded
uploadFile.xdata = file.xdata;
- uploadFile.ws.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
}
} else {
- p13uploadFileCancel();
+ p13uploadFileTransferDone();
}
}
// Used to cancel the entire transfer.
function p13uploadFileCancel(button, tag) {
- if (uploadFile != null) {
- if (uploadFile.ws != null) {
- uploadFile.ws.Stop();
- uploadFile.ws = null;
- }
- uploadFile = null;
- }
- setDialogMode(0); // Close any dialog boxes if present
+ if (uploadFile != null) { files.sendText(JSON.stringify({ action: 'uploadcancel', reqid: uploadFile.xfilePtr })); uploadFile = null; }
+ p13uploadFileTransferDone();
+ }
+
+ // Used to cancel the entire transfer.
+ function p13uploadFileTransferDone() {
+ uploadFile = null; // No more files to upload, clean up.
+ setDialogMode(0); // Close the dialog box
+ p13folderup(9999); // Refresh the current folder
}
// Receive upload ack from the mesh agent, use this to keep sending more data
- function p13gotUploadData(data) {
- var cmd = JSON.parse(data);
+ function p13gotUploadData(cmd) {
if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
-
- if (cmd.action == 'uploadstart') {
- p13uploadNextPart(false);
- for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } // Send 8 more blocks of 4 k to full the websocket.
- } else if (cmd.action == 'uploadack') {
- p13uploadNextPart(false);
- } else if (cmd.action == 'uploaddone') {
- if (uploadFile.ws != null) { uploadFile.ws.Stop(); uploadFile.ws = null; }
- if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadReconnect(); } else { p13uploadFileCancel(); }
- } else if (cmd.action == 'uploaderror') {
- p13uploadFileCancel();
+ switch (cmd.action) {
+ case 'uploadstart': { p13uploadNextPart(false); for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } break; } // Send 8 more blocks of 16k to fill the websocket.
+ case 'uploadack': { p13uploadNextPart(false); break; }
+ case 'uploaddone': { if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadNextFile(); } else { p13uploadFileTransferDone(); } break; }
+ case 'uploaderror': { p13uploadFileCancel(); break; }
}
}
// Push the next part of the file into the websocket. If dataPriming is true, push more data only if it's not the last block of the file.
function p13uploadNextPart(dataPriming) {
- var data = uploadFile.xdata;
- var start = uploadFile.xptr;
+ var data = uploadFile.xdata, start = uploadFile.xptr;
if (start >= data.byteLength) {
- uploadFile.ws.sendCtrlMsg('{"ctrlChannel":"102938","type":"close"}');
+ files.sendText(JSON.stringify({ action: 'uploaddone', reqid: uploadFile.xfilePtr }));
} else {
var end = uploadFile.xptr + 16384;
if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
- var datapart = data.slice(start, end);
- uploadFile.ws.send(datapart);
+ var dataslice = new Uint8Array(data.slice(start, end))
+ if ((dataslice[0] == 123) || (dataslice[0] == 0)) {
+ var datapart = new Uint8Array(end - start + 1);
+ datapart.set(dataslice, 1); // Add a zero char at the start of the send, this will indicate that it's not a JSON command.
+ files.send(datapart);
+ } else {
+ files.send(dataslice); // The data does not start with 0 or 123 "{" so it can't be confused for JSON.
+ }
uploadFile.xptr = end;
Q('d2progressBar').value = end;
}