More work on mobile guest sharing site.
Ylian Saint-Hilaire committed
Jan 5, 2022 at 02:43 UTC
ce93843a514d272de943e3c8ad7542569c254547
3 files changed
+4217
-1578
sample-config-advanced.json
+1
-1
@@ -1,5 +1,5 @@
1
{
2
- "$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json",
2
+ "$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json",
3
"__comment__": "This is a sample configuration file, all values and sections that start with underscore (_) are ignored. Edit a section and remove the _ in front of the name. Refer to the user's guide for details.",
4
"settings": {
5
"_cert": "myserver.mydomain.com",
views/sharing-mobile-old.handlebars
new
+2486
@@ -0,0 +1,2486 @@
1
+<!DOCTYPE html>
2
+<html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
3
+<head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
7
+ <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
8
+ <meta name="format-detection" content="telephone=no" />
9
+ <meta name="robots" content="noindex,nofollow">
10
+ <link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS" />
11
+ <link type="text/css" href="styles/style-sharing.css" media="screen" rel="stylesheet" title="CSS" />
12
+ <link type="text/css" href="styles/xterm.css" media="screen" rel="stylesheet" title="CSS" />
13
+ <link rel="apple-touch-icon" href="/favicon-303x303.png" />
14
+ <meta name="apple-mobile-web-app-capable" content="yes">
15
+ <meta name="apple-mobile-web-app-status-bar-style" content="#ffffff">
16
+ <meta name="apple-mobile-web-app-title" content="{{{title}}}">
17
+ <script type="text/javascript" src="scripts/common-0.0.1{{min}}.js"></script>
18
+ <script type="text/javascript" src="scripts/amt-redir-ws-0.1.0{{{min}}}.js"></script>
19
+ <script type="text/javascript" src="scripts/amt-wsman-ws-0.2.0{{{min}}}.js"></script>
20
+ <script type="text/javascript" src="scripts/agent-redir-ws-0.1.1{{{min}}}.js"></script>
21
+ <script type="text/javascript" src="scripts/agent-redir-rtc-0.1.0{{{min}}}.js"></script>
22
+ <script type="text/javascript" src="scripts/agent-desktop-0.0.2{{min}}.js"></script>
23
+ <script type="text/javascript" src="scripts/amt-desktop-0.0.2{{min}}.js"></script>
24
+ <script type="text/javascript" src="scripts/amt-terminal-0.0.2{{min}}.js"></script>
25
+ <script type="text/javascript" src="scripts/zlib{{min}}.js"></script>
26
+ <script type="text/javascript" src="scripts/zlib-inflate{{min}}.js"></script>
27
+ <script type="text/javascript" src="scripts/zlib-adler32{{min}}.js"></script>
28
+ <script type="text/javascript" src="scripts/zlib-crc32{{min}}.js"></script>
29
+ <script type="text/javascript" src="scripts/amt-terminal-0.0.2{{min}}.js"></script>
30
+ <script type="text/javascript" src="scripts/xterm{{{min}}}.js"></script>
31
+ <script type="text/javascript" src="scripts/xterm-addon-fit{{{min}}}.js"></script>
32
+ <script keeplink=1 type="text/javascript" src="scripts/filesaver.min.js"></script>
33
+ <title>{{{title}}}</title>
34
+ <style>
35
+
36
+ .deskButton {
37
+ box-shadow: 0px 0px 10px #000;
38
+ border-radius:20px;
39
+ position:absolute;
40
+ right:10px;
41
+ top:10px;
42
+ cursor:pointer;
43
+ background-color:#AAA;
44
+ z-index:1000;
45
+ }
46
+
47
+ .menuButton{
48
+ box-shadow: 0px 0px 10px #000;
49
+ border-radius:10px;
50
+ display:inline-block;
51
+ width:120px;
52
+ background-color:#AAA;
53
+ text-align:center;
54
+ padding:8px;
55
+ cursor:pointer;
56
+ margin:10px;
57
+ z-index:1000;
58
+ }
59
+
60
+ #dialog {
61
+ z-index:1000;
62
+ background-color:#EEE;
63
+ box-shadow:0px 0px 15px #666;
64
+ font-family:Arial,Helvetica,sans-serif;
65
+ border-radius:5px;
66
+ position:fixed;
67
+ top:90px;
68
+ width:300px;
69
+ }
70
+
71
+ .night #dialog {
72
+ color: black;
73
+ background-color:#AAA;
74
+ }
75
+
76
+ </style>
77
+</head>
78
+<body style="overflow:hidden;background-color:black;margin:0;padding:0;border:0;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
79
+ <div id=p11 class="noselect" style="overflow:hidden;position:absolute;left:0;top:0;right:0;bottom:32px;display:none">
80
+ <div id=p10dialog style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:30px;width:300px;left:30px;display:none">
81
+ <div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
82
+ <div style=padding:5px>Keyboard Shortcuts Customization</div>
83
+ <div style=width:100%;margin:6px></div>
84
+ </div>
85
+ <div style="margin-right:16px;margin-left:8px"><div id=p10dialog2 style="margin:auto;margin:3px"></div></div>
86
+ <div style="padding:10px;margin-bottom:20px"><input type="button" value="OK" style="float:right;width:80px" onclick="deskCustomizeKeysEx()"></div>
87
+ </div>
88
+ <img id="deskkeybutton1" src="images/mobile-desk-exit.png" class="deskButton" style="top:10px;display:none" onclick="exitButton(event)" />
89
+ <img id="deskkeybutton3a" src="images/mobile-desk-menu-open.png" class="deskButton" style="top:60px;display:none" onclick="toggleMenu(false)" />
90
+ <img id="deskkeybutton3b" src="images/mobile-desk-menu-close.png" class="deskButton" style="top:60px;display:none" onclick="toggleMenu(true)" />
91
+ <img id="deskkeybutton4a" src="images/mobile-desk-mouse-left.png" class="deskButton" style="top:110px;display:none" onclick="deskChangeMouseButton(0)" />
92
+ <img id="deskkeybutton4b" src="images/mobile-desk-mouse-right.png" class="deskButton" style="top:110px;display:none" onclick="deskChangeMouseButton(1)" />
93
+ <img id="deskkeybutton5a" src="images/mobile-desk-scale-out.png" class="deskButton" style="top:160px;display:none" onclick="deskChangeFullscreenZoom()" />
94
+ <img id="deskkeybutton5b" src="images/mobile-desk-scale-in.png" class="deskButton" style="top:160px;display:none" onclick="deskChangeFullscreenZoom()" />
95
+ <img id="deskkeybutton2a" src="images/mobile-desk-keyboard-open.png" class="deskButton" style="top:210px;display:none" onclick="toggleKeyboard()" />
96
+ <img id="deskkeybutton2b" src="images/mobile-desk-keyboard-close.png" class="deskButton" style="top:210px;display:none" onclick="toggleKeyboard()" />
97
+ <div style="position:absolute;top:0;left:0;z-index:200;opacity:0;width:1px;height:1px">
98
+ <input id="softKeyboard" autocapitalize="off" autocomplete="off" type="text" spellcheck="false" style="z-index:200;opacity:0;width:1px;height:1px" onfocus="keyboardFocusChange()" onblur="keyboardFocusChange()" />
99
+ </div>
100
+ <div id="deskButtonMenu" style="display:none;position:absolute;top:10px;left:10px;right:55px;bottom:10px;z-index:1000"></div>
101
+ <div id=deskarea0 style="position:absolute;top:0px;left:0px;right:0px;bottom:0px">
102
+ <div id=deskarea1 class="areaHead" style="line-height:24px">
103
+ <div class="toright2">
104
+ <span id="p11power"></span>
105
+ <input id="deskFullScreen" type="button" value="Full Screen" style="display:none" onkeypress="return false" onkeydown="return false" onclick="deskToggleFull(event)" class="mR" />
106
+ <input id="deskActionsSettings" type="button" value="Settings..." onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" class="mR" />
107
+ <div id="deskRecordIcon" class='deskareaicon' title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px"></div>
108
+ </div>
109
+ <div>
110
+ <div id="idx_deskFullBtn2" onclick=deskToggleFull(event)> ✖</div>
111
+ <span id=connectbutton1span><input type=button id=connectbutton1 cmenu="deskConnectButton" value="Connect" onclick=connectDesktop(event,3) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
112
+ <span id=connectbutton1hspan> <input type=button id=connectbutton1h value="HW Connect" title="Connect using Intel AMT hardware KVM" onclick=connectDesktop(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
113
+ <span id=disconnectbutton1span> <input type=button id=disconnectbutton1 value="Disconnect" onclick=connectDesktop(event,0) onkeypress="return false" onkeydown="return false" /></span>
114
+ <span id="deskstatus">Disconnected</span><span id="deskmetadata"></span>
115
+ </div>
116
+ </div>
117
+ <div id=deskarea3x style="max-height:calc(100vh - 60px);height:calc(100vh - 60px);">
118
+ <div id=DeskParent>
119
+ <canvas id=Desk width=640 height=480 oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event) onmousewheel=dmousewheel(event)></canvas>
120
+ </div>
121
+ <div id=p11DeskConsoleMsg style="display:none;text-align:left;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=clearConsoleMsg()></div>
122
+ </div>
123
+ <div id=deskarea4 class="areaFoot" style="min-height:24px">
124
+ <div class="toright2">
125
+ <span id="DeskLatency" title="Desktop Session Latency"></span>
126
+ <span id="DeskTimer" style="display:none" title="Session time"></span>
127
+ <select id=termdisplays style="display:none" onchange=deskSetDisplay(event) onkeypress="return false" onkeydown="return false"></select>
128
+ <span id=DeskSaveImageButton title="Save a screenshot of the remote desktop"><img src='images/icon-camera.png' onclick=deskSaveImage() height=16 width=16 style=padding-top:2px /></span>
129
+ </div>
130
+ <div style="height:22px">
131
+ <select id="deskkeys">
132
+ <option value=10>Ctrl+Alt+Del</option>
133
+ <option value=5>Win</option>
134
+ <option value=0>Win+Down</option>
135
+ <option value=1>Win+Up</option>
136
+ <option value=2>Win+L</option>
137
+ <option value=3>Win+M</option>
138
+ <option value=4>Shift+Win+M</option>
139
+ <option value=6>Win+R</option>
140
+ <option value=7>Alt-F4</option>
141
+ <option value=8>Ctrl-W</option>
142
+ <option value=9>Alt-Tab</option>
143
+ <option value=11>Win+Left</option>
144
+ <option value=12>Win+Right</option>
145
+ </select>
146
+ <input id="DeskWD" type=button value="Send" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()" />
147
+ <input id="DeskClip" style="" type="button" value="Clipboard" onkeypress="return false" onkeydown="return false" onclick="showDeskClip()" />
148
+ <input id="DeskType" style="" type="button" value="Type" onkeypress="return false" onkeydown="return false" onclick="showDeskType()" />
149
+ <label><span id="DeskControlSpan" title="Toggle mouse and keyboard input"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false" onclick="toggleKvmControl()" />Input</span></label>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </div>
154
+ <div id=p12 class="noselect" style="overflow:hidden;position:absolute;left:0;top:0;right:0;bottom:32px;display:none;background-color:black">
155
+ <div id="p12warning" onclick=showFeaturesDlg()>
156
+ <div class="icon2"></div>
157
+ <div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p12warninga">, click here to enable it.</span></div>
158
+ </div>
159
+ <div id="p12warning2" onclick=showPowerActionDlg()>
160
+ <div class="icon2"></div>
161
+ <div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
162
+ </div>
163
+ <div class="areaHead" style="position:absolute;top:0;left:0;right:0;height:24px">
164
+ <div class="toright2">
165
+ <div id="termRecordIcon" class='deskareaicon' title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
166
+ <div id="p12power" style="margin-top:3px;margin-right:4px;float:right"></div>
167
+ </div>
168
+ <div>
169
+ <span id="connectbutton2span"><input type="button" id="connectbutton2" cmenu="termConnectButton" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
170
+ <span id="disconnectbutton2span"> <input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false" /></span>
171
+ <span id="termstatus">Disconnected</span><span id="termtitle"></span>
172
+ </div>
173
+ </div>
174
+ <div id="termarea3xdiv" style="position:absolute;top:28px;bottom:28px;left:0;right:0"></div>
175
+ <div class="areaFoot" style="position:absolute;bottom:0;left:0;right:0;height:24px">
176
+ <div class="toright2">
177
+ <span id="TermLatency" title="Terminal Session Latency"></span>
178
+ <span id="TermTimer" title="Session time"></span>
179
+ <span id="terminalSettingsButtons" style="display:none">
180
+ <input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="CR+LF" title="Toggle what the return key will send" onclick="termToggleCr()" />
181
+ <input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()" />
182
+ <input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()" />
183
+ </span>
184
+ <span id="terminalSizeDropDown" style="display:none">
185
+ <select id="termSizeList" onkeypress="return false"><option value="1">80x25</option><option value="2">100x30</option></select>
186
+ </span>
187
+ <span id="specialKeyDropDown">
188
+ <select id="specialkeylist" onkeypress="return false"></select>
189
+ <input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />
190
+ </span>
191
+ </div>
192
+ <div>
193
+
194
+ <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')" />
195
+ <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')" />
196
+ <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')" />
197
+ <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')" style="display:none" />
198
+ <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()" style="display:none" />
199
+ </div>
200
+ </div>
201
+ <div id=p12TermConsoleMsg style="display:none;text-align:left;cursor:pointer;position:absolute;left:30px;top:45px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p12clearConsoleMsg()></div>
202
+ </div>
203
+ <div id=p13 class="noselect" style="overflow:hidden;position:absolute;left:0;top:0;right:0;bottom:32px;display:none;background-color:white">
204
+ <div id="p13toolbar" style="position:absolute;left:0;top:0;right:0;bottom:28px">
205
+ <div class="areaHead">
206
+ <div class="toright2">
207
+ <div id="filesRecordIcon" class='deskareaicon' title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
208
+ <div id="p13power" style="margin-top:3px;margin-right:4px;float:right"></div>
209
+ </div>
210
+ <div>
211
+ <input id=p13Connect value="Connect" onclick=connectFiles(event) type="button" />
212
+ <span id=p13Status>Disconnected</span>
213
+ </div>
214
+ </div>
215
+ <div id="fileArea2" class="areaHead2" valign=bottom>
216
+ <div id="p13rightOfButtons" class="toright2"></div>
217
+ <div>
218
+ <input type=button id=p13FolderUp disabled="disabled" onclick="p13folderup()" value="Up" />
219
+ <input type=button id=p13SelectAllButton disabled="disabled" onclick="p13selectallfile()" value="Select All" />
220
+ <input type=button id=p13RenameFileButton disabled="disabled" value="Rename" onclick="p13renamefile()" />
221
+ <input type=button id=p13DeleteFileButton disabled="disabled" value="Delete" onclick="p13deletefile()" />
222
+ <input type=button id=p13ViewFileButton disabled="disabled" value="Edit" onclick="p13viewfile()" />
223
+ <input type=button id=p13NewFolderButton disabled="disabled" value="New Folder" onclick="p13createfolder()" />
224
+ <input type=button id=p13UploadButton disabled="disabled" value="Upload" onclick="p13uploadFile()" />
225
+ <input type=button id=p13CutButton disabled="disabled" value="Cut" onclick="p13copyFile(1)" />
226
+ <input type=button id=p13CopyButton disabled="disabled" value="Copy" onclick="p13copyFile(0)" />
227
+ <input type=button id=p13PasteButton disabled="disabled" value="Paste" onclick="p13pasteFile()" />
228
+ <input type=button id=p13ZipButton disabled="disabled" value="Zip" onclick="p13zipFiles()" />
229
+ <input type=button id=p13RefreshButton disabled="disabled" value="Refresh" onclick="p13folderup(9999)" />
230
+ <input type=button id=p13FindButton disabled="disabled" value="Find" onclick="p13findfile()" />
231
+ </div>
232
+ </div>
233
+ <div class="areaHead3" style="line-height:28px">
234
+ <div class="toright2">
235
+ <select id=p13sortdropdown onchange=p13updateFiles()>
236
+ <option value=1 selected="selected">Sort by name</option>
237
+ <option value=2>Sort by size</option>
238
+ <option value=3>Sort by date</option>
239
+ <option value=4>Descend by name</option>
240
+ <option value=5>Descend by size</option>
241
+ <option value=6>Descend by date</option>
242
+ </select>
243
+ </div>
244
+ <div> <span id="p13currentpath"></span></div>
245
+ </div>
246
+ <div id="fileArea4" style="height:calc(100vh - 146px)">
247
+ <div id=p13FilesConsoleMsg style="display:none;text-align:left;cursor:pointer;position:absolute;left:30px;top:165px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p13clearConsoleMsg()></div>
248
+ <div id="p13filetable" style="width:100%;height:100%">
249
+ <div id="p13bigok" style="display:none"><b>✓</b></div>
250
+ <div id="p13bigfail" style="display:none"><b>✗</b></div>
251
+ <span id="p13files"></span>
252
+ </div>
253
+ </div>
254
+ </div>
255
+ <div class="areaFoot" style="position:absolute;left:0;right:0;bottom:0;height:28px">
256
+ <span id="p13bottomstatus"></span>
257
+ </div>
258
+ </div>
259
+ <div id=xfooter style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px;margin:0;padding:0">
260
+ <table id=xfooterMenu cellpadding=0 cellspacing=0 style="height:32px;width:100%;color:white;cursor:pointer;table-layout:fixed"></table>
261
+ </div>
262
+ <div id=dialog class="noselect" style="display:none">
263
+ <div id=dialogHeader>
264
+ <div tabindex=0 id=id_dialogclose onclick=setDialogMode() onkeypress="if (event.key == 'Enter') setDialogMode()">✖</div>
265
+ <div id=id_dialogtitle></div>
266
+ </div>
267
+ <div id=dialogBody>
268
+ <div id=dialog1>
269
+ <div id=id_dialogMessage style=""></div>
270
+ </div>
271
+ <div id=dialog2 style="">
272
+ <div id=id_dialogOptions></div>
273
+ </div>
274
+ <div id=dialog7 style="margin:auto;margin:3px">
275
+ <div id="d7meshkvm">
276
+ <h4 style="width:100%;border-bottom:1px solid gray">Agent Remote Desktop</h4>
277
+ <table style="width:100%">
278
+ <tr>
279
+ <td>
280
+ Quality
281
+ </td>
282
+ <td style="width:100px">
283
+ <select id="d7bitmapquality" style="float:right;width:200px" dir="rtl"></select>
284
+ </td>
285
+ </tr>
286
+ <tr>
287
+ <td>
288
+ Scaling
289
+ </td>
290
+ <td style="width:100px">
291
+ <select id="d7bitmapscaling" style="float:right;width:200px" dir="rtl">
292
+ <option selected=selected value=1024>100%</option>
293
+ <option value=896>87.5%</option>
294
+ <option value=768>75%</option>
295
+ <option value=640>62.5%</option>
296
+ <option value=512>50%</option>
297
+ <option value=384>37.5%</option>
298
+ <option value=256>25%</option>
299
+ <option value=128>12.5%</option>
300
+ </select>
301
+ </td>
302
+ </tr>
303
+ <tr>
304
+ <td>
305
+ Rate
306
+ </td>
307
+ <td style="width:100px">
308
+ <select id="d7framelimiter" style="float:right;width:200px" dir="rtl">
309
+ <option selected=selected value=50>Fast</option>
310
+ <option value=100>Medium</option>
311
+ <option value=400>Slow</option>
312
+ <option value=1000>Very slow</option>
313
+ </select>
314
+ </td>
315
+ </tr>
316
+ <tr>
317
+ <td></td>
318
+ <td>
319
+ <label style="display:block" id="d7deskAutoLockLabel"><input type="checkbox" id="d7deskAutoLock" />Lock on Disconnect</label>
320
+ </td>
321
+ </tr>
322
+ </table>
323
+ </div>
324
+ <div id="d7amtkvm">
325
+ <h4 style="width:100%;border-bottom:1px solid gray">Intel® AMT Hardware KVM</h4>
326
+ <table style="width:100%">
327
+ <tr>
328
+ <td>Encoding</td>
329
+ <td style="width:100px">
330
+ <select id="d7desktopmode" style="float:right;width:200px">
331
+ <option value="1">RLE8, Fastest</option>
332
+ <option value="2">RLE16, Recommended</option>
333
+ <option value="3">RAW8, Slow</option>
334
+ <option value="4">RAW16, Very Slow</option>
335
+ </select>
336
+ </td>
337
+ </tr>
338
+ </table>
339
+ </div>
340
+ </div>
341
+ </div>
342
+ <div id="idx_dlgButtonBar">
343
+ <input id="idx_dlgCancelButton" type="button" value="Cancel" style="" onclick="dialogclose(0)">
344
+ <input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
345
+ <div><input id="idx_dlgDeleteButton" type="button" value="Delete" style="display:none" onclick="dialogclose(2)"></div>
346
+ </div>
347
+ </div>
348
+ <script>
349
+ var sessionActivity = null;
350
+ var desktop = null;
351
+ var agentPresent = true;
352
+ var intelAmtPresent = false;
353
+ var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 100, localkeymap: false };
354
+ var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
355
+ var domain = '{{{domain}}}';
356
+ var domainUrl = '{{{domainurl}}}';
357
+ var authCookie = '{{{authCookie}}}';
358
+ var viewOnly = parseInt('{{{viewOnly}}}');
359
+ var urlargs = parseUriArgs();
360
+ var debugmode = urlargs.debug;
361
+ var attemptWebRTC = false;
362
+ var updateSessionTimer = null;
363
+ var deskKeyboardShortcuts = [];
364
+ var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel® AMT Connected"];
365
+ var nodeName = decodeURIComponent('{{{nodeName}}}');
366
+ var webPageFullScreen = false;
367
+ var expire = '{{{expire}}}';
368
+ if (expire != '') {
369
+ QH('p11power', printFlexDateTime(new Date(parseInt(expire))));
370
+ QH('p12power', printFlexDateTime(new Date(parseInt(expire))));
371
+ QH('p13power', printFlexDateTime(new Date(parseInt(expire))));
372
+ }
373
+ var features = parseInt('{{{features}}}');
374
+ var features2 = parseInt('{{{features2}}}');
375
+
376
+ // Load desktop settings
377
+ var t = null;
378
+ try { t = localStorage.getItem('desktopsettings'); } catch (ex) { }
379
+ if (t != null) { try { desktopsettings = JSON.parse(t); } catch (ex) { } }
380
+ if (((features2 & 1) == 0) && (desktopsettings.quality > 60)) { desktopsettings.quality = 60; }
381
+
382
+ // Terminal
383
+ var terminal = null;
384
+ var xterm = null;
385
+ var xtermfit = null;
386
+ var xtermResizeTimer = null;
387
+
388
+ // Files
389
+ var files = null
390
+
391
+ // Console messages timers
392
+ var p11DeskConsoleMsgTimer = null;
393
+ var p12TermConsoleMsgTimer = null;
394
+ var p13FilesConsoleMsgTimer = null;
395
+
396
+ function start() {
397
+ window.onresize = center;
398
+ center();
399
+ document.onkeypress = ondeskkeypress;
400
+ document.onkeydown = ondeskkeydown;
401
+ document.onkeyup = ondeskkeyup;
402
+ //document.onkeypress = ondockeypress;
403
+ //document.onkeydown = ondockeydown;
404
+ //document.onkeyup = ondockeyup;
405
+ setupDesktop();
406
+ setupTerminal();
407
+ setupFiles();
408
+
409
+ // Set the document title
410
+ if (nodeName.length > 0) { document.title += ' - ' + nodeName; }
411
+
412
+ // View only mode
413
+ if (viewOnly == 1) {
414
+ QV('deskkeys', false);
415
+ QV('DeskWD', false);
416
+ QV('DeskClip', false);
417
+ QV('DeskType', false);
418
+ QV('DeskControlSpan', false);
419
+ }
420
+
421
+ // Setup upload drag & drop
422
+ Q('p13filetable').addEventListener('drop', p13fileDragDrop, false);
423
+ Q('p13filetable').addEventListener('dragover', p13fileDragOver, false);
424
+ Q('p13filetable').addEventListener('dragleave', p13fileDragLeave, false);
425
+
426
+ // Setup feature visibility
427
+ QV('LeftMenuDesktop', features & 2);
428
+ QV('LeftMenuTerminal', features & 1);
429
+ QV('LeftMenuFiles', features & 4);
430
+ if (features & 2) { go(11); } // Goto desktop
431
+ else if (features & 1) { go(12); } // Goto terminal
432
+ else if (features & 4) { go(13); } // Goto files
433
+ deskAdjust();
434
+
435
+ // Set the user's desktop shortcut keys
436
+ deskKeyboardShortcuts = [];
437
+ var deskKeyboardShortcutsStr = '0x0A002E,0x100000,0x100028,0x100026,0x10004C,0x10004D,0x11004D,0x100052,0x020073,0x080057,0x020009,0x100025,0x100027'.split(',');
438
+ for (var i in deskKeyboardShortcutsStr) { deskKeyboardShortcuts.push(parseInt(deskKeyboardShortcutsStr[i])); }
439
+ updateDeskShortcutKeys();
440
+ //updateTermShortcutKeys();
441
+ }
442
+
443
+ //
444
+ // Desktop
445
+ //
446
+
447
+ function isInputAllowed() { return (viewOnly != 1) && (Q('DeskControl').checked == true); }
448
+ function clearConsoleMsg() { QH('p11DeskConsoleMsg', ''); }
449
+
450
+ function deskAdjust() {
451
+ if ((xxcurrentView == 12) && (terminal != null) && (xtermfit != null)) { xtermfit.fit(); } // Terminal
452
+ QS('fileArea4')['height'] = 'calc(100vh - ' + (90 + Q('fileArea2').clientHeight) + 'px)'; // Files
453
+
454
+ if (fullscreen) {
455
+ QS('Desk')['margin-top'] = null;
456
+ QS('Desk')['margin-bottom'] = null;
457
+ QS('deskarea3x')['padding-right'] = '55px';
458
+ QS('Desk').width = '100%';
459
+ QS('Desk').height = '100%';
460
+ var parentH = Q('p11').clientHeight, parentW = Q('p11').clientWidth;
461
+ var deskH = Q('deskarea3x').clientHeight, deskW = Q('deskarea3x').clientWidth - 55;
462
+ if (parentH > deskH) { QS('deskarea3x').top = ((parentH - deskH) / 2) + 'px'; } else { QS('deskarea3x').top = null; }
463
+ if (parentW > deskW) { QS('deskarea3x').left = ((parentW - deskW) / 2) + 'px'; } else { QS('deskarea3x').left = null; }
464
+ } else {
465
+ var parentH = Q('DeskParent').clientHeight, parentW = Q('DeskParent').clientWidth;
466
+ var deskH = Q('Desk').height, deskW = Q('Desk').width;
467
+
468
+ // Fixed aspect ratio
469
+ if ((parentH / parentW) > (deskH / deskW)) {
470
+ var hNew = ((deskH * parentW) / deskW) + 'px';
471
+ QS('Desk').height = hNew;
472
+ QS('Desk').width = '100%';
473
+ } else {
474
+ var wNew = ((deskW * parentH) / deskH) + 'px';
475
+ QS('Desk').height = '100%';
476
+ QS('Desk').width = wNew;
477
+ }
478
+ QS('Desk')['margin-top'] = null;
479
+ QS('deskarea3x')['padding-right'] = null;
480
+ }
481
+ }
482
+
483
+ function setupDesktop() {
484
+ // Setup the remote desktop
485
+ if (desktop != null) { desktop.Stop(); desktop = null; }
486
+
487
+ // If the device desktop is already connected in multi-desktop, use that.
488
+ if (desktop == null) {
489
+ // Device is not already connected, just setup a blank canvas
490
+ QH('DeskParent', '<canvas id=Desk oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
491
+
492
+ // Setup the mouse wheel
493
+ Q('Desk').addEventListener('DOMMouseScroll', function (e) { return dmousewheel(e); });
494
+ Q('Desk').addEventListener('mousewheel', function (e) { return dmousewheel(e); });
495
+ }
496
+ updateDesktopButtons();
497
+ deskAdjust();
498
+ updateMetadata(desktop, 'deskmetadata');
499
+ }
500
+
501
+ // Show and enable the right buttons
502
+ function updateDesktopButtons() {
503
+ var deskState = 0;
504
+ if (desktop != null) { deskState = desktop.State; }
505
+
506
+ // Show the right buttons
507
+ QV('disconnectbutton1span', (deskState != 0));
508
+ QV('connectbutton1span', (deskState == 0) && (agentPresent));
509
+ QV('connectbutton1hspan', (deskState == 0) && (intelAmtPresent));
510
+
511
+ // Show the right settings
512
+ QV('d7meshkvm', agentPresent && ((deskState == 0) || (desktop.contype == 1)));
513
+ QV('d7amtkvm', intelAmtPresent && ((deskState == 0) || (desktop.contype == 2)));
514
+
515
+ // Enable buttons
516
+ QE('connectbutton1', agentPresent);
517
+ QE('connectbutton1h', intelAmtPresent);
518
+ //QV('DeskClip', agentPresent && ((desktop == null) || (desktop.contype != 2))); // Clipboard not supported on macOS
519
+ QV('DeskClip', false); // Clipboard not supported on this page
520
+ QE('DeskClip', deskState == 3);
521
+ QE('DeskType', deskState == 3);
522
+ QV('DeskWD', viewOnly != 1);
523
+ QE('DeskWD', deskState == 3);
524
+ QV('deskkeys', viewOnly != 1);
525
+ QE('deskkeys', deskState == 3);
526
+
527
+ // Display this only if we have Chat & Notify permissions
528
+ QV('DeskSaveImageButton', (deskState == 3) && (Q('Desk')['toBlob'] != null));
529
+ QV('DeskControlSpan', viewOnly != 1);
530
+ QV('deskActionsBtn', true);
531
+ QV('deskActionsSettings', (deskState != 3));
532
+ Q('DeskControl').checked = true;
533
+ QS('DeskControlSpan').color = Q('DeskControl').checked ? null : 'red';
534
+ }
535
+
536
+ // Used to translate incoming agent console messages
537
+ var agentConsoleMessages = ['', "Waiting for user to grant access...", "Denied", "Failed to start remote terminal session, {0} ({1})", "Timeout", "Received invalid network data"];
538
+ function formatAgentConsoleMessage(msg, msgid, msgargs) {
539
+ var r;
540
+ if (msgargs == null) { msgargs = []; }
541
+ while (msgargs.length < 3) { msgargs.push(''); } // We need to call the format function in a way that works with older browsers and minifier, can't use apply() or ...
542
+ if (msgid && (msgid < agentConsoleMessages.length)) { r = EscapeHtml(format(agentConsoleMessages[msgid], (msgargs[0]), (msgargs[1]), (msgargs[2]))); } else { r = EscapeHtml(msg); }
543
+ return r.split('\n').join('<br />') + '<br /><br />';
544
+ }
545
+
546
+ function connectDesktop(e, contype, tsid, consent) {
547
+ if (xxdialogMode) return;
548
+ if ((e != null) && (e.shiftKey != false) && (contype == 3)) { contype = 1; } // If the shift key is not pressed, don't try to ask for session list.
549
+ QV('p11DeskSessionSelector', false);
550
+ p11clearConsoleMsg();
551
+ if (desktop == null) {
552
+ if (contype == 2) {
553
+ // Setup the Intel AMT remote desktop
554
+ //if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop, 2); return; }
555
+ desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
556
+ desktop.debugmode = debugmode;
557
+ desktop.onStateChanged = onDesktopStateChange;
558
+ desktop.m.stopInput = (viewOnly == 1);
559
+ desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
560
+ desktop.m.useZRLE = (desktopsettings.encoding < 3);
561
+ desktop.m.localKeyMap = desktopsettings.localkeymap;
562
+ desktop.m.showmouse = desktopsettings.showmouse;
563
+ desktop.m.onScreenSizeChange = deskAdjust;
564
+ desktop.m.onKvmData = function (x) {
565
+ //console.log('onKvmData (' + x.length + '): ' + x);
566
+ // Send the presense probe only once if needed.
567
+ if (x.length == 0) { if (!desktop.m._sentPresence) { desktop.m._sentPresence = true; desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 })); } return; }
568
+ var data = null;
569
+ try { data = JSON.parse(x); } catch (e) { }
570
+ if ((data != null) && (data.action != null)) {
571
+ if (data.action == 'restart') {
572
+ // Clear WebRTC channel
573
+ webRtcDesktopReset();
574
+ desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 }));
575
+ } else if ((data.action == 'present') && (webRtcDesktop == null)) {
576
+ // Setup WebRTC channel
577
+ webRtcDesktop = { platform: data.platform };
578
+ var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };
579
+ if (typeof RTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new RTCPeerConnection(configuration); }
580
+ else if (typeof webkitRTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new webkitRTCPeerConnection(configuration); }
581
+
582
+ webRtcDesktop.webchannel = webRtcDesktop.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
583
+ webRtcDesktop.webchannel.onopen = function () {
584
+ // Switch to software KVM
585
+ //if (urlvars && urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Open'); }
586
+ console.log('WebRTC Data Channel Open');
587
+ Q('deskstatus').textContent = StatusStrs[desktop.State] + ", Soft-KVM";
588
+ desktop.m.hold(true);
589
+ webRtcDesktop.webRtcActive = true;
590
+ webRtcDesktop.softdesktop = CreateKvmDataChannel(webRtcDesktop.webchannel, CreateAgentRemoteDesktop('Desk', Q('id_mainarea')), desktop.m);
591
+ webRtcDesktop.softdesktop.m.setRotation(desktop.m.rotation);
592
+ webRtcDesktop.softdesktop.m.onScreenSizeChange = deskAdjust;
593
+ if (desktopsettings.quality) { webRtcDesktop.softdesktop.m.CompressionLevel = desktopsettings.quality; } // Number from 1 to 100. 50 or less is best.
594
+ if (desktopsettings.scaling) { webRtcDesktop.softdesktop.m.ScalingLevel = desktopsettings.scaling; }
595
+ webRtcDesktop.softdesktop.Start();
596
+
597
+ // Check if we can get remote file access
598
+ // ###BEGIN###{DesktopInbandFiles}
599
+ /*
600
+ QV('go24', true); // Files
601
+ downloadFile = null;
602
+ p24files = webRtcDesktop.softdesktop;
603
+ p24targetpath = '';
604
+ webRtcDesktop.softdesktop.onControlMsg = onFilesControlData;
605
+ webRtcDesktop.softdesktop.sendCtrlMsg(JSON.stringify({ action: 'ls', reqid: 1, path: '' })); // Ask for the root folder
606
+ */
607
+ // ###END###{DesktopInbandFiles}
608
+ }
609
+ webRtcDesktop.webchannel.onclose = function (event) {
610
+ //if (urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Closed'); }
611
+ console.log('WebRTC Data Channel Closed');
612
+ webRtcDesktopReset();
613
+ }
614
+ webRtcDesktop.webrtc.onicecandidate = function (e) {
615
+ if (e.candidate == null) {
616
+ desktop.m.sendKvmData(JSON.stringify({ action: 'offer', ver: 1, sdp: webRtcDesktop.webrtcoffer.sdp }));
617
+ } else {
618
+ webRtcDesktop.webrtcoffer.sdp += ('a=' + e.candidate.candidate + '\r\n'); // New candidate, add it to the SDP
619
+ }
620
+ }
621
+ webRtcDesktop.webrtc.oniceconnectionstatechange = function () {
622
+ if ((webRtcDesktop != null) && (webRtcDesktop.webrtc != null) && ((webRtcDesktop.webrtc.iceConnectionState == 'disconnected') || (webRtcDesktop.webrtc.iceConnectionState == 'failed'))) { /*console.log('WebRTC ICE Failed');*/ webRtcDesktopReset(); }
623
+ }
624
+ webRtcDesktop.webrtc.createOffer(function (offer) {
625
+ // Got the offer
626
+ webRtcDesktop.webrtcoffer = offer;
627
+ webRtcDesktop.webrtc.setLocalDescription(offer, function () { }, webRtcDesktopReset);
628
+ }, webRtcDesktopReset, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
629
+ } else if ((data.action == 'answer') && (webRtcDesktop != null)) {
630
+ // Complete the WebRTC channel
631
+ webRtcDesktop.webrtc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: data.sdp }), function () { }, webRtcDesktopReset);
632
+ }
633
+ }
634
+ };
635
+ desktop.Start(null, 16994, '*', '*', 0);
636
+ desktop.contype = 2;
637
+ } else if ((contype == null) || (contype == 1) || (contype == 3)) {
638
+ // Setup the Mesh Agent remote desktop
639
+ desktop = CreateAgentRedirect(null, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, null, domainUrl);
640
+ desktop.m.stopInput = (viewOnly == 1);
641
+ desktop.m.mouseCursorActive(true);
642
+ desktop.debugmode = debugmode;
643
+ desktop.m.debugmode = debugmode;
644
+ desktop.attemptWebRTC = attemptWebRTC;
645
+ desktop.options = {};
646
+ if (tsid != null) { desktop.options.tsid = tsid; }
647
+ if (consent != null) { desktop.options.consent = consent; }
648
+ desktop.onStateChanged = onDesktopStateChange;
649
+ desktop.onConsoleMessageChange = function () {
650
+ if (desktop.consoleMessage) {
651
+ Q('p11DeskConsoleMsg').innerHTML += formatAgentConsoleMessage(desktop.consoleMessage, desktop.consoleMessageId, desktop.consoleMessageArgs);
652
+ QV('p11DeskConsoleMsg', true);
653
+ if (p11DeskConsoleMsgTimer != null) { clearTimeout(p11DeskConsoleMsgTimer); }
654
+ if (desktop.consoleMessageTimeout) { p11DeskConsoleMsgTimer = setTimeout(p11clearConsoleMsg, desktop.consoleMessageTimeout * 1000); }
655
+ } else {
656
+ p11clearConsoleMsg();
657
+ }
658
+ }
659
+ desktop.onMetadataChange = function (metadata) { updateMetadata(desktop, 'deskmetadata'); }
660
+ desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
661
+ desktop.m.ScalingLevel = desktopsettings.scaling;
662
+ if (desktopsettings.framerate) { desktop.m.FrameRateTimer = desktopsettings.framerate; }
663
+ desktop.m.onDisplayinfo = deskDisplayInfo;
664
+ desktop.m.onScreenSizeChange = deskAdjust;
665
+ desktop.Start(null);
666
+ desktop.latency.callback = function (ms) { console.log('latency', ms); updateSessionTime(); };
667
+ desktop.contype = 1;
668
+ }
669
+ } else {
670
+ // Disconnect and clean up the remote desktop
671
+ desktop.Stop();
672
+ webRtcDesktopReset();
673
+ desktop = null;
674
+ //if (pluginHandler != null) { pluginHandler.callHook('onDesktopDisconnect'); }
675
+ }
676
+ }
677
+
678
+ function updateMetadata(conn, elementid) {
679
+ var str = '', viewerCount = 0;
680
+ if (conn && (conn.State == 3)) {
681
+ if (conn.metadata && conn.metadata.users) { for (var i in conn.metadata.users) { viewerCount += conn.metadata.users[i]; } }
682
+ if (viewerCount > 1) { str = '<span onclick=showSessionMetadata(1) style=cursor:pointer>' + format(", {0} watching", viewerCount) + '</span>'; }
683
+ }
684
+ QH('deskmetadata', str);
685
+ if ((conn == desktop) && (xxdialogTag == ('sessionMetadata1'))) { showSessionMetadata(1); }
686
+ }
687
+
688
+ function showSessionMetadata(cid) {
689
+ if (xxdialogMode && (xxdialogTag != ('sessionMetadata' + cid))) return;
690
+ if (xxdialogMode) { setDialogMode(0); }
691
+ var conn = null;
692
+ if (cid == 1) { conn = desktop; }
693
+ if (conn && conn.metadata) {
694
+ var x = '';
695
+ if (conn.metadata.startTime) { x += addHtmlValue4("Start Time", printDateTime(new Date(conn.metadata.startTime))); }
696
+ if (conn.metadata.users) {
697
+ for (var i in conn.metadata.users) {
698
+ var val = (conn.metadata.users[i] == 1) ? "1 connection" : format("{0} connections", conn.metadata.users[i]);
699
+ var username = i.split('/')[2];
700
+ if ((users != null) && (users[i] != null)) { username = users[i].name; }
701
+ x += addHtmlValue4(format("User \"{0}\"", username), val);
702
+ }
703
+ }
704
+ setDialogMode(2, "Session Information", 1, null, x, 'sessionMetadata' + cid);
705
+ }
706
+ }
707
+
708
+ function p11clearConsoleMsg() { QH('p11DeskConsoleMsg', ''); QV('p11DeskConsoleMsg', false); if (p11DeskConsoleMsgTimer) { clearTimeout(p11DeskConsoleMsgTimer); p11DeskConsoleMsgTimer = null; } }
709
+ function p12clearConsoleMsg() { QH('p12TermConsoleMsg', ''); QV('p12TermConsoleMsg', false); if (p12TermConsoleMsgTimer) { clearTimeout(p12TermConsoleMsgTimer); p12TermConsoleMsgTimer = null; } }
710
+ function p13clearConsoleMsg() { QH('p13FilesConsoleMsg', ''); QV('p13FilesConsoleMsg', false); if (p13FilesConsoleMsgTimer) { clearTimeout(p13FilesConsoleMsgTimer); p13FilesConsoleMsgTimer = null; } }
711
+
712
+ var webRtcDesktop = null;
713
+ function webRtcDesktopReset() {
714
+ if (webRtcDesktop == null) return;
715
+ if (webRtcDesktop.softdesktop != null) { webRtcDesktop.softdesktop.Stop(); webRtcDesktop.softdesktop = null; }
716
+ if (webRtcDesktop.webchannel != null) { try { webRtcDesktop.webchannel.close(); } catch (e) { } webRtcDesktop.webchannel = null; }
717
+ if (webRtcDesktop.webrtc != null) { try { webRtcDesktop.webrtc.close(); } catch (e) { } webRtcDesktop.webrtc = null; }
718
+ webRtcDesktop = null;
719
+ // Switch back to hardware KVM
720
+ if (desktop && desktop.m) {
721
+ desktop.m.hold(false);
722
+ Q('deskstatus').textContent = StatusStrs[desktop.State];
723
+ }
724
+ // ###BEGIN###{DesktopInbandFiles}
725
+ /*
726
+ p24files = null;
727
+ p24downloadFileCancel() // If any downloads are in process, cancel them.
728
+ p24uploadFileCancel(); // If any uploads are in process, cancel them.
729
+ QV('go24', false); // Files
730
+ if (currentView == 24) { go(14); }
731
+ */
732
+ // ###END###{DesktopInbandFiles}
733
+ }
734
+
735
+ function onDesktopStateChange(xdesktop, state) {
736
+ var xstate = state;
737
+ if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
738
+ var str = StatusStrs[xstate];
739
+ if ((desktop != null) && (desktop.webRtcActive == true)) { str += ", WebRTC"; }
740
+ //if (desktop.m.stopInput == true) { str += ', Loopback'; }
741
+ QH('deskstatus', str);
742
+ QV('deskFullScreen', state == 3);
743
+ QV('deskActionsSettings', state != 3);
744
+ switch (state) {
745
+ case 0:
746
+ // Stop recording
747
+ if (desktop.m.recordedData != null) { deskRecordSession(); }
748
+
749
+ // Disconnect and clean up the remote desktop
750
+ desktop.Stop();
751
+ desktop = null;
752
+ QV('termdisplays', false);
753
+ QV('deskRecordIcon', false);
754
+ if (fullscreen == true) { deskToggleFull(); }
755
+ webRtcDesktopReset();
756
+ deskPreferedStickyDisplay = 0;
757
+ break;
758
+ case 2:
759
+ break;
760
+ case 3:
761
+ if (desktop && (desktop.serverIsRecording == true)) { QV('deskRecordIcon', true); }
762
+ desktop.startTime = new Date();
763
+ if (updateSessionTimer == null) { updateSessionTimer = setInterval(updateSessionTime, 1000); }
764
+ break;
765
+ default:
766
+ //console.log('Unknown onDesktopStateChange state', state);
767
+ break;
768
+ }
769
+ updateDesktopButtons();
770
+ deskAdjust();
771
+ setTimeout(deskAdjust, 50);
772
+ updateMetadata(desktop, 'deskmetadata');
773
+ }
774
+
775
+ function updateSessionTime() {
776
+ // Desktop
777
+ var latencyStr = '', seconds = 0;
778
+ if (desktop && desktop.startTime) {
779
+ if (desktop.latency && (desktop.latency.current >= 0)) { latencyStr = format('{0} ms, ', desktop.latency.current); }
780
+ seconds = Math.floor((new Date() - desktop.startTime) / 1000);
781
+ QH('DeskTimer', latencyStr + zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2));
782
+ } else {
783
+ QH('DeskTimer', '');
784
+ }
785
+
786
+ if (desktop == null) { clearInterval(updateSessionTimer); updateSessionTimer = null; }
787
+ }
788
+
789
+ function showDesktopSettings() {
790
+ if (xxdialogMode) return;
791
+ applyDesktopSettings();
792
+ updateDesktopButtons();
793
+ setDialogMode(7, "Remote Desktop Settings", 3, showDesktopSettingsChanged);
794
+ }
795
+
796
+ function showDesktopSettingsChanged() {
797
+ desktopsettings.encoding = d7desktopmode.value;
798
+ desktopsettings.quality = d7bitmapquality.value;
799
+ desktopsettings.scaling = d7bitmapscaling.value;
800
+ desktopsettings.framerate = d7framelimiter.value;
801
+ desktopsettings.swapmouse = d7deskSwapMouse.checked;
802
+ desktopsettings.remotekeymap = d7deskRemoteKeyMap.checked;
803
+ desktopsettings.localkeymap = d7localKeyMap.checked;
804
+ localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
805
+ applyDesktopSettings();
806
+ if (desktop) {
807
+ if (desktop.contype == 1) {
808
+ desktop.m.SwapMouse = desktopsettings.swapmouse;
809
+ desktop.m.remoteKeyMap = desktopsettings.remotekeymap;
810
+ if (desktop.State != 0) {
811
+ desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate);
812
+ }
813
+ }
814
+ if (desktop.contype == 2) {
815
+ if (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); }
816
+ }
817
+ }
818
+ }
819
+
820
+ function applyDesktopSettings() {
821
+ var r = '', ops = (features2 & 1) ? [90, 80, 70, 60, 50, 40, 30, 20, 10, 5, 1] : [60, 50, 40, 30, 20, 10, 5, 1]
822
+ for (var i in ops) { r += '<option value=' + ops[i] + '>' + ops[i] + '%</option>'; }
823
+ QH('d7bitmapquality', r);
824
+ d7desktopmode.value = desktopsettings.encoding;
825
+ d7bitmapquality.value = 40; // Default value
826
+ if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
827
+ d7bitmapscaling.value = desktopsettings.scaling;
828
+ if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; } else { d7framelimiter.value = 100; }
829
+ if (desktopsettings.swapmouse != null) { d7deskSwapMouse.checked = desktopsettings.swapmouse; }
830
+ if (desktopsettings.remotekeymap != null) { d7deskRemoteKeyMap.checked = desktopsettings.remotekeymap; }
831
+ if (desktopsettings.localkeymap) { d7localKeyMap.checked = desktopsettings.localkeymap; }
832
+ }
833
+
834
+ function toggleMenu(x) {
835
+ if (xxdialogMode) return;
836
+ QV('deskButtonMenu', fullscreen && !x && (xxcurrentView == 11));
837
+ QV('termButtonMenu', fullscreen && !x && (xxcurrentView == 12));
838
+ QV('deskkeybutton3a', fullscreen && x);
839
+ QV('deskkeybutton3b', fullscreen && !x);
840
+ }
841
+
842
+ function deskChangeMouseButton(x) {
843
+ if (xxdialogMode) return;
844
+ if (desktop == null) return;
845
+ desktop.m.SwapMouse = !desktop.m.SwapMouse;
846
+ QV('deskkeybutton4a', fullscreen && (!desktop.m.SwapMouse));
847
+ QV('deskkeybutton4b', fullscreen && (desktop.m.SwapMouse));
848
+ }
849
+
850
+ function deskChangeFullscreenZoom() {
851
+ if (xxdialogMode) return;
852
+ if (xxcurrentView == 11) {
853
+ if (desktop == null) return;
854
+ if (fullscreenzoom == 1) { fullscreenzoom = 0.5; } else { fullscreenzoom = 1; }
855
+ QV('deskkeybutton5a', fullscreen && (fullscreenzoom == 1));
856
+ QV('deskkeybutton5b', fullscreen && (fullscreenzoom != 1));
857
+ QS('deskarea3x').width = (desktop.m.ScreenWidth * fullscreenzoom) + 'px';
858
+ QS('deskarea3x').height = (desktop.m.ScreenHeight * fullscreenzoom) + 'px';
859
+ deskAdjust();
860
+ }
861
+ if (xxcurrentView == 12) {
862
+ if (terminal == null) return;
863
+ xterm.setOption('fontSize', (xterm.getOption('fontSize') == 15) ? 10 : 15)
864
+ }
865
+ }
866
+
867
+ var fullscreen = false;
868
+ var fullscreenzoom = 1;
869
+ function deskToggleFull(e) {
870
+ var xtermActive = !((urlargs.xterm === 0) || ((terminal != null) && (xterm == null)));
871
+ fullscreen = !fullscreen;
872
+ if (fullscreen) {
873
+ QV('deskarea1', false);
874
+ QV('deskarea4', false);
875
+ QV('xfooter', false);
876
+ QS('p11').bottom = '0px';
877
+ QS('deskarea0').overflow = 'scroll';
878
+ QS('deskarea3x').width = (desktop.m.ScreenWidth * fullscreenzoom) + 'px';
879
+ QS('deskarea3x').height = QS('deskarea3x')['max-height'] = (desktop.m.ScreenHeight * fullscreenzoom) + 'px';
880
+ QS('deskarea3x')['padding-right'] = '55px';
881
+ if (xtermActive) {
882
+ // XTerm terminal
883
+ //QS('termTable')['position'] = 'absolute';
884
+ //QS('termTable')['top'] = QS('termTable')['bottom'] = QS('termTable')['left'] = QS('termTable')['right'] = '0';
885
+ } else {
886
+ // Legacy terminal
887
+ //QS('termTable')['height'] = '100%';
888
+ //QS('termTable')['max-height'] = '100%';
889
+ }
890
+ } else {
891
+ QV('deskarea1', true);
892
+ QV('deskarea4', true);
893
+ QV('xfooter', true);
894
+ QS('p11').bottom = '32px';
895
+ QS('deskarea0').overflow = null;
896
+ QS('deskarea3x').width = null;
897
+ QS('deskarea3x').height = QS('deskarea3x')['max-height'] = 'calc(100vh - 60px)';
898
+ QS('deskarea3x')['padding-right'] = null;
899
+ if (xtermActive) {
900
+ // XTerm terminal
901
+ //QS('termTable')['position'] = null;
902
+ //QS('termTable')['top'] = QS('termTable')['bottom'] = QS('termTable')['left'] = QS('termTable')['right'] = null;
903
+ } else {
904
+ // Legacy terminal
905
+ //QS('termTable')['height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
906
+ //QS('termTable')['max-height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
907
+ }
908
+ }
909
+
910
+ inputAllowed = true; // todo
911
+
912
+ // Show full screen buttons if needed
913
+ QV('deskkeybutton1', fullscreen);
914
+ if (xxcurrentView == 11) { // Desktop panel is being shown (11 = Desktop, 12 = Terminal)
915
+ // Move shortcut key to desktop position
916
+ QS('deskkeybutton2a').top = QS('deskkeybutton2b').top = '210px';
917
+ // Move the zoom button to normal or top position
918
+ QS('deskkeybutton5a').top = QS('deskkeybutton5b').top = (inputAllowed) ? '160px' : '60px'; // Zoom
919
+ QV('deskkeybutton2a', fullscreen && inputAllowed);
920
+ QV('deskkeybutton2b', false);
921
+ QV('deskkeybutton3a', fullscreen && inputAllowed);
922
+ QV('deskkeybutton3b', false);
923
+ QV('deskkeybutton4a', fullscreen && inputAllowed && (!desktop.m.SwapMouse));
924
+ QV('deskkeybutton4b', fullscreen && inputAllowed && (desktop.m.SwapMouse));
925
+ QV('deskkeybutton5a', fullscreen && (fullscreenzoom == 1));
926
+ QV('deskkeybutton5b', fullscreen && (fullscreenzoom != 1));
927
+ }
928
+ if (xxcurrentView == 12) {
929
+ // Move right buttons to terminal position
930
+ //QS('deskkeybutton3a').top = QS('deskkeybutton3b').top = '60px'; // Shortcuts
931
+ //QS('deskkeybutton5a').top = QS('deskkeybutton5b').top = '110px'; // Zoom
932
+ QS('deskkeybutton2a').top = QS('deskkeybutton2b').top = '110px'; // Keyboard
933
+ QV('deskkeybutton2a', fullscreen);
934
+ QV('deskkeybutton2b', false);
935
+ QV('deskkeybutton3a', fullscreen);
936
+ QV('deskkeybutton3b', false);
937
+ QV('deskkeybutton4a', false);
938
+ QV('deskkeybutton4b', false);
939
+ QV('deskkeybutton5a', false);
940
+ QV('deskkeybutton5a', false);
941
+ //QV('deskkeybutton5a', xterm.getOption('fontSize') == 15);
942
+ //QV('deskkeybutton5b', xterm.getOption('fontSize') != 15);
943
+ }
944
+
945
+ if (xxcurrentView == 11) { deskAdjust(); }
946
+ updateDesktopButtons();
947
+ //adjustPanels();
948
+ //setTimeout(adjustPanels, 10);
949
+ //setTimeout(function() { xtermfit.fit(); }, 10);
950
+ if (xterm != null) { if (xxcurrentView == 12) { xtermfit.fit(); xterm.focus(); } }
951
+ }
952
+
953
+ function mdeskAdjust(mod, sw, sh, cv) {
954
+ if (!mod || !sw || !sh || !cv) return;
955
+
956
+ // Check if we are in single desktop mode
957
+ if (cv.id == 'Desk') { deskAdjust(); return; }
958
+
959
+ // Figure out and adjust the size to fill the width of the div
960
+ var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
961
+ var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
962
+ xw = realw + Math.floor((tw - (xw * realw)) / xw);
963
+ vsize.y = vsize.y * (xw / vsize.x);
964
+ vsize.x = xw;
965
+ var mh = vsize.y, mw = vsize.x;
966
+ if (mod.State != 0) { mh = vsize.y; mw = (sw / sh) * vsize.y; }
967
+ QS(cv.id)['max-height'] = mh + 'px';
968
+ QS(cv.id)['max-width'] = mw + 'px';
969
+ QS(cv.id)['margin-top'] = '0';
970
+ QS(cv.id)['margin-bottom'] = '0';
971
+ }
972
+
973
+ // Remote desktop special key combos for Windows
974
+ function deskSendKeys() {
975
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
976
+ var ks = Q('deskkeys').value;
977
+ if (ks == 0) { // WIN+Down arrow
978
+ if (desktop.contype == 2) {
979
+ desktop.m.sendkey([[0xffe7, 1], [0xff54, 1], [0xff54, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Down arrow press, Down arrow release, Meta-left release
980
+ } else {
981
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 40], [desktop.m.KeyAction.UP, 40], [desktop.m.KeyAction.EXUP, 0x5B]]); // Agent: L-Winkey press, Down arrow press, Down arrow release, L-Winkey release
982
+ }
983
+ } else if (ks == 1) { // WIN+Up arrow
984
+ if (desktop.contype == 2) {
985
+ desktop.m.sendkey([[0xffe7, 1], [0xff52, 1], [0xff52, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Up arrow press, Up arrow release, Meta-left release
986
+ } else {
987
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 38], [desktop.m.KeyAction.UP, 38], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, Up arrow press, Up arrow release, L-Winkey release
988
+ }
989
+ } else if (ks == 2) { // WIN+L arrow
990
+ if (desktop.contype == 2) {
991
+ desktop.m.sendkey([[0xffe7, 1], [0x6c, 1], [0x6c, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'l' press, 'l' release, Meta-left release
992
+ } else {
993
+ desktop.sendCtrlMsg('{"action":"lock"}');
994
+ //desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,76],[desktop.m.KeyAction.UP,76],[desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, 'L' press, 'L' release, L-Winkey release
995
+ //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXDOWN, 0x5B);
996
+ //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.DOWN, 76);
997
+ //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.UP, 76);
998
+ //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXUP, 0x5B);
999
+ }
1000
+ } else if (ks == 3) { // WIN+M arrow
1001
+ if (desktop.contype == 2) {
1002
+ desktop.m.sendkey([[0xffe7, 1], [0x6d, 1], [0x6d, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'm' press, 'm' release, Meta-left release
1003
+ } else {
1004
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 77], [desktop.m.KeyAction.UP, 77], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, 'M' press, 'M' release, L-Winkey release
1005
+ }
1006
+ } else if (ks == 4) { // Shift+WIN+M arrow
1007
+ if (desktop.contype == 2) {
1008
+ desktop.m.sendkey([[0xffe1, 1], [0xffe7, 1], [0x6d, 1], [0x6d, 0], [0xffe7, 0], [0xffe1, 0]]); // Intel AMT: Shift-left down, Meta-left down, 'm' press, 'm' release, Meta-left release, Shift-left release
1009
+ } else {
1010
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.DOWN, 16], [desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 77], [desktop.m.KeyAction.UP, 77], [desktop.m.KeyAction.EXUP, 0x5B], [desktop.m.KeyAction.UP, 16]]); // MeshAgent: L-shift press, L-Winkey press, 'M' press, 'M' release, L-Winkey release, L-shift release
1011
+ }
1012
+ } else if (ks == 5) { // WIN
1013
+ if (desktop.contype == 2) {
1014
+ desktop.m.sendkey([[0xffe7, 1], [0xffe7, 0]]); // Intel AMT: Meta-left down, Meta-left release
1015
+ } else {
1016
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, L-Winkey release
1017
+ }
1018
+ } else if (ks == 6) { // WIN+R
1019
+ if (desktop.contype == 2) {
1020
+ desktop.m.sendkey([[0xffe7, 1], [0x72, 1], [0x72, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'r' press, 'r' release, Meta-left release
1021
+ } else {
1022
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 82], [desktop.m.KeyAction.UP, 82], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, 'R' press, 'R' release, L-Winkey release
1023
+ }
1024
+ } else if (ks == 7) { // ALT-F4
1025
+ if (desktop.contype == 2) {
1026
+ desktop.m.sendkey([[0xffe9, 1], [0xffc1, 1], [0xffc1, 0], [0xffe9, 0]]); // Intel AMT: Alt down, 'F4' press, 'F4' release, Alt release
1027
+ } else {
1028
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 18], [desktop.m.KeyAction.DOWN, 115], [desktop.m.KeyAction.UP, 115], [desktop.m.KeyAction.EXUP, 18]]); // MeshAgent: Alt press, 'F4' press, 'F4' release, Alt release
1029
+ }
1030
+ } else if (ks == 8) { // CTRL-W
1031
+ if (desktop.contype == 2) {
1032
+ desktop.m.sendkey([[0xffe3, 1], [0x77, 1], [0x77, 0], [0xffe3, 0]]); // Intel AMT: Ctrl down, 'w' press, 'w' release, Ctrl release
1033
+ } else {
1034
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 17], [desktop.m.KeyAction.DOWN, 87], [desktop.m.KeyAction.UP, 87], [desktop.m.KeyAction.EXUP, 17]]); // MeshAgent: Ctrl press, 'W' press, 'W' release, Ctrl release
1035
+ }
1036
+ } else if (ks == 9) { // ALT-TAB
1037
+ if (desktop.contype == 2) {
1038
+ desktop.m.sendkey([[0xffe9, 1], [0xff09, 1], [0xff09, 0], [0xffe9, 0]]); // Intel AMT: Alt down, 'TAB' press, 'TAB' release, Alt release
1039
+ } else {
1040
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 18], [desktop.m.KeyAction.DOWN, 9], [desktop.m.KeyAction.UP, 9], [desktop.m.KeyAction.EXUP, 18]]); // MeshAgent: Alt press, 'TAB' press, 'TAB' release, Alt release
1041
+ }
1042
+ } else if (ks == 10) { // CTRL-ALT-DEL
1043
+ desktop.m.sendcad();
1044
+ } else if (ks == 11) { // WIN-LEFT
1045
+ if (desktop.contype == 2) {
1046
+ desktop.m.sendkey([[0xffe7, 1], [0xff51, 1], [0xff51, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Left arrow press, Left arrow release, Meta-left release
1047
+ } else {
1048
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 37], [desktop.m.KeyAction.UP, 37], [desktop.m.KeyAction.EXUP, 0x5B]]);
1049
+ }
1050
+ } else if (ks == 12) { // WIN-RIGHT
1051
+ if (desktop.contype == 2) {
1052
+ desktop.m.sendkey([[0xffe7, 1], [0xff53, 1], [0xff53, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Right arrow press, Right arrow release, Meta-left release
1053
+ } else {
1054
+ desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 39], [desktop.m.KeyAction.UP, 39], [desktop.m.KeyAction.EXUP, 0x5B]]);
1055
+ }
1056
+ }
1057
+ }
1058
+
1059
+
1060
+ var gotKeyPressEvent = false;
1061
+ function ondeskkeypress(e, t) {
1062
+ setSessionActivity();
1063
+ if (desktop && !xxdialogMode && (xxcurrentView == 11)) {
1064
+ gotKeyPressEvent = true;
1065
+ Q('softKeyboard').value = '';
1066
+ // Check what keys we are allows to send
1067
+ var inputAllowed = true; // TODO
1068
+ if (inputAllowed == false) return false;
1069
+ return desktop.m.handleKeys(e);
1070
+ }
1071
+ if (terminal && !xxdialogMode && (xxcurrentView == 12) (t !== 1)) {
1072
+ if (e.altKey == true) { return true; }
1073
+ gotKeyPressEvent = true;
1074
+ Q('softKeyboard').value = '';
1075
+ var k = 0;
1076
+ if (e.charCode != 0) { k = e.charCode; } else if (e.keyCode != 0) { k = e.keyCode; }
1077
+ if (k != 0) {
1078
+ if (terminal.urlname == 'sshterminalrelay.ashx') {
1079
+ // SSH
1080
+ terminal.socket.send('~' + String.fromCharCode(k));
1081
+ } else {
1082
+ // Agent
1083
+ terminal.sendText(String.fromCharCode(k));
1084
+ }
1085
+ }
1086
+ return false;
1087
+ }
1088
+ }
1089
+
1090
+ function ondeskkeydown(e, t) {
1091
+ setSessionActivity();
1092
+ if (desktop && !xxdialogMode && (xxcurrentView == 11)) {
1093
+ gotKeyPressEvent = false;
1094
+ Q('softKeyboard').value = '';
1095
+ // Check what keys we are allows to send
1096
+ var inputAllowed = true; // TODO
1097
+ if (inputAllowed == false) return false;
1098
+ return desktop.m.handleKeyDown(e);
1099
+ }
1100
+ if (terminal && !xxdialogMode && (xxcurrentView == 12) && (t !== 1)) {
1101
+ if (e.altKey == true) { return true; }
1102
+ Q('softKeyboard').value = '';
1103
+ gotKeyPressEvent = false;
1104
+ var k = 0;
1105
+ if (e.charCode != 0) { k = e.charCode; } else if (e.keyCode != 0) { k = e.keyCode; }
1106
+ if (k == 8) { terminal.sendText(String.fromCharCode(k)); } // Enter and backspace
1107
+ else if (e.ctrlKey && (k >= 64) && (k <= 95)) {
1108
+ // Ctrl keys
1109
+ if (terminal.urlname == 'sshterminalrelay.ashx') {
1110
+ // SSH
1111
+ terminal.socket.send('~' + String.fromCharCode(k - 64));
1112
+ } else {
1113
+ // Agent
1114
+ terminal.sendText(String.fromCharCode(k - 64));
1115
+ }
1116
+ }
1117
+ }
1118
+ }
1119
+
1120
+ function ondeskkeyup(e, t) {
1121
+ setSessionActivity();
1122
+ if (desktop && !xxdialogMode && (xxcurrentView == 11)) {
1123
+ var inputStr = Q('softKeyboard').value;
1124
+ Q('softKeyboard').value = '';
1125
+ // Check what keys we are allows to send
1126
+ var inputAllowed = true; // TODO
1127
+ if (inputAllowed == false) return false;
1128
+ if ((gotKeyPressEvent == false) && (inputStr.length > 0) && desktop.m.SendKeyUnicode) {
1129
+ // This is a mobile keyboard, we need to send that is in the input control.
1130
+ var inputchar = inputStr[inputStr.length - 1].charCodeAt(0);
1131
+ desktop.m.SendKeyUnicode(desktop.m.KeyAction.DOWN, inputchar);
1132
+ desktop.m.SendKeyUnicode(desktop.m.KeyAction.UP, inputchar);
1133
+ } else {
1134
+ return desktop.m.handleKeyUp(e);
1135
+ }
1136
+ }
1137
+ if (terminal && !xxdialogMode && (xxcurrentView == 12) && (gotKeyPressEvent == false) && (t !== 1)) {
1138
+ if (e.altKey == true) { return true; }
1139
+ var inputStr = Q('softKeyboard').value;
1140
+ Q('softKeyboard').value = '';
1141
+ if (terminal.urlname == 'sshterminalrelay.ashx') {
1142
+ // SSH
1143
+ terminal.socket.send('~' + inputStr);
1144
+ } else {
1145
+ // Agent
1146
+ if (inputStr) terminal.sendText(inputStr);
1147
+ }
1148
+ return false;
1149
+ }
1150
+ }
1151
+
1152
+
1153
+ // Remote desktop typing
1154
+ function showDeskType() {
1155
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
1156
+ Q('DeskType').blur();
1157
+ var x = '<div>' + "Enter text and click OK to remotely type it using a US english keyboard. Make sure to place the remote cursor at the correct position before proceeding." + '<div>';
1158
+ x += '<textarea id=d2typeText style="margin-top:5px;width:100%;height:184px;resize:none" maxlength=2000></textarea>';
1159
+ setDialogMode(2, "Remote Keyboard Entry", 3, showDeskTypeEx, x);
1160
+ Q('d2typeText').focus();
1161
+ }
1162
+
1163
+ var AmtDeskTypeTimer = null;
1164
+ var AmtDeskTypeContent = null;
1165
+ var DeskTypeTranslate = { 39: 222, 42: 106, 43: 107, 44: 188, 45: 189, 46: 190, 47: 191, 59: 186, 61: 187, 91: 219, 92: 220, 93: 221, 96: 192, 191: 111 };
1166
+ var DeskTypeShiftTranslate = { 33: 49, 34: 222, 35: 51, 36: 52, 37: 53, 38: 55, 40: 57, 41: 48, 58: 186, 60: 188, 62: 190, 63: 191, 64: 50, 94: 54, 95: 189, 106: 56, 107: 187, 123: 219, 124: 220, 125: 221, 126: 192 };
1167
+ function showDeskTypeEx() {
1168
+ var txt = Q('d2typeText').value, ltxt = Q('d2typeText').value.toUpperCase(), x = [], shift = false;
1169
+ if (desktop.contype == 2) {
1170
+ // Intel AMT
1171
+ for (var i in txt) { var a = txt.charCodeAt(i); x.push([a, 1], [a, 0]); }
1172
+ AmtDeskTypeContent = x;
1173
+ AmtDeskTypeTimer = setInterval(function () {
1174
+ var key = AmtDeskTypeContent.shift();
1175
+ if (desktop) { desktop.m.sendkey(key[0], key[1]); }
1176
+ if ((desktop == null) || (AmtDeskTypeContent.length == 0)) { clearInterval(AmtDeskTypeTimer); AmtDeskTypeContent = null; }
1177
+ }, 10);
1178
+ } else {
1179
+ // MeshAgent
1180
+ for (var i in txt) {
1181
+ var a = txt.charCodeAt(i), b = ltxt.charCodeAt(i);
1182
+ if (((a >= 65) && (a <= 90)) || ((a >= 97) && (a <= 122))) {
1183
+ if ((a == b) && (shift == false)) { x.push([desktop.m.KeyAction.DOWN, 16]); shift = true; } // LShift down
1184
+ if ((a != b) && (shift == true)) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // LShift up
1185
+ } else if ((a >= 48) && (a <= 57)) {
1186
+ if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
1187
+ } else if (DeskTypeTranslate[a]) {
1188
+ if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
1189
+ b = DeskTypeTranslate[a];
1190
+ } else if (DeskTypeShiftTranslate[a]) {
1191
+ if (shift == false) { x.push([desktop.m.KeyAction.DOWN, 16]); shift = true; } // LShift down
1192
+ b = DeskTypeShiftTranslate[a];
1193
+ }
1194
+ x.push([desktop.m.KeyAction.DOWN, b], [desktop.m.KeyAction.UP, b]);
1195
+ }
1196
+ if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
1197
+ desktop.m.SendKeyMsgKC(x);
1198
+ }
1199
+ }
1200
+
1201
+ /*
1202
+ // Show clipboard dialog
1203
+ function showDeskClip() {
1204
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
1205
+ Q('DeskClip').blur();
1206
+ var x = '';
1207
+ x += '<input id=dlgClipGet type=button value="Get Clipboard" style=width:120px onclick=showDeskClipGet()>';
1208
+ x += '<input id=dlgClipSet type=button value="Set Clipboard" style=width:120px onclick=showDeskClipSet()>';
1209
+ x += '<div id=dlgClipStatus style="display:inline-block;margin-left:8px" ></div>';
1210
+ x += '<textarea id=d2clipText style="width:100%;height:184px;resize:none" maxlength=65535></textarea>';
1211
+ x += '<input type=button value="Close" style=width:80px;float:right onclick=dialogclose(0)><div style=height:26px;margin-top:3px><span id=linuxClipWarn style=display:none>' + "Remote clipboard is valid for 60 seconds." + '</span> </div><div></div>';
1212
+ setDialogMode(2, "Remote Clipboard", 8, null, x, 'clipboard');
1213
+ Q('d2clipText').focus();
1214
+ }
1215
+
1216
+ function showDeskClipGet() {
1217
+ if (desktop == null || desktop.State != 3) return;
1218
+ meshserver.send({ action: 'msg', type: 'getclip', nodeid: currentNode._id });
1219
+ }
1220
+
1221
+ function showDeskClipSet() {
1222
+ if (desktop == null || desktop.State != 3) return;
1223
+ meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: Q('d2clipText').value });
1224
+ //QV('linuxClipWarn', currentNode && currentNode.agent && (currentNode.agent.id > 4) && (currentNode.agent.id != 21) && (currentNode.agent.id != 22));
1225
+ }
1226
+ */
1227
+
1228
+ // Send CTRL-ALT-DEL
1229
+ function sendCAD() {
1230
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
1231
+ desktop.m.sendcad();
1232
+ }
1233
+
1234
+ // Toggle mouse and keyboard input
1235
+ function toggleKvmControl() { QS('DeskControlSpan').color = Q('DeskControl').checked ? null : 'red'; }
1236
+
1237
+ // Save the desktop image to file
1238
+ function deskSaveImage() {
1239
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
1240
+ var d = new Date(), n = "Desktop" + '-' + d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + '-' + ('0' + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);
1241
+ Q('Desk')['toBlob'](function (blob) { saveAs(blob, n + '.png'); });
1242
+ }
1243
+
1244
+ function deskDisplayInfo(sender, displays, selDisplay) {
1245
+ var displayCount = 0, displaySelector = '';
1246
+ for (var i in displays) {
1247
+ displayCount++;
1248
+ displaySelector += '<option' + ((selDisplay == i) ? ' selected' : '') + ' value=' + i + '>' + displays[i] + '</option>';
1249
+ if ((deskPreferedStickyDisplay == i) && (selDisplay != deskPreferedStickyDisplay)) { desktop.m.SetDisplay(i); }
1250
+ deskPreferedStickyDisplay = -1;
1251
+ }
1252
+ QH('termdisplays', displaySelector);
1253
+ QV('termdisplays', displayCount > 1);
1254
+ }
1255
+
1256
+ function deskGetDisplayNumbers(e) { desktop.m.GetDisplayNumbers(); }
1257
+ var deskPreferedStickyDisplay = -1;
1258
+ function deskSetDisplay(e) { desktop.m.SetDisplay(deskPreferedStickyDisplay = parseInt(Q('termdisplays').value)); Q('termdisplays').blur(); }
1259
+
1260
+ // Double click detection. This is important for macOS.
1261
+ var dblClickDetectArgs = { t: 0, x: 0, y: 0 };
1262
+ function dblClickDetect(e) {
1263
+ if (e.buttons != 1) return;
1264
+ var t = Date.now();
1265
+ if (((t - dblClickDetectArgs.t) < 250) && (Math.abs(e.clientX - dblClickDetectArgs.x) < 2) && (Math.abs(e.clientY - dblClickDetectArgs.y) < 2)) {
1266
+ if (!xxdialogMode && desktop != null && isInputAllowed()) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousedblclick(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousedblclick(e); } }
1267
+ }
1268
+ dblClickDetectArgs.t = t;
1269
+ dblClickDetectArgs.x = e.clientX;
1270
+ dblClickDetectArgs.y = e.clientY;
1271
+ }
1272
+
1273
+ function dmousedown(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) { if (fullscreen) { e.addx = Q('deskarea0').scrollLeft * (1 / fullscreenzoom); e.addy = Q('deskarea0').scrollTop * (1 / fullscreenzoom); } desktop.m.mousedown(e); } }
1274
+ function dmouseup(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) { if (fullscreen) { e.addx = Q('deskarea0').scrollLeft * (1 / fullscreenzoom); e.addy = Q('deskarea0').scrollTop * (1 / fullscreenzoom); } desktop.m.mouseup(e); } }
1275
+ function dmousemove(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) { if (fullscreen) { e.addx = Q('deskarea0').scrollLeft * (1 / fullscreenzoom); e.addy = Q('deskarea0').scrollTop * (1 / fullscreenzoom); } desktop.m.mousemove(e); } }
1276
+ function dmousewheel(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null) && desktop.m.mousewheel) { if (fullscreen) { e.addx = Q('deskarea0').scrollLeft * (1 / fullscreenzoom); e.addy = Q('deskarea0').scrollTop * (1 / fullscreenzoom); } desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
1277
+
1278
+ var keyboardShown = false;
1279
+ var keyboardShownTimer = null;
1280
+ var fullScreenMode = false;
1281
+ function toggleKeyboard() {
1282
+ if (xxdialogMode) return;
1283
+ if (keyboardShownTimer != null) { clearTimeout(keyboardShownTimer); }
1284
+ if (keyboardShown) { Q('softKeyboard').blur(); keyboardShown = false; } else { Q('softKeyboard').focus(); keyboardShown = true; }
1285
+ QV('deskkeybutton2a', fullscreen && !keyboardShown);
1286
+ QV('deskkeybutton2b', fullscreen && keyboardShown);
1287
+ }
1288
+
1289
+ function keyboardFocusChange() {
1290
+ keyboardShownTimer = setTimeout(function () {
1291
+ keyboardShownTimer = null;
1292
+ keyboardShown = (Q('softKeyboard') == document.activeElement);
1293
+ QV('deskkeybutton2a', fullscreen && !keyboardShown);
1294
+ QV('deskkeybutton2b', fullscreen && keyboardShown);
1295
+ }, 100);
1296
+ }
1297
+
1298
+ function exitButton() {
1299
+ if (xxdialogMode) return;
1300
+ QV('deskButtonMenu', false);
1301
+ QV('termButtonMenu', false);
1302
+ if (fullscreenzoom == 1) {
1303
+ deskToggleFull();
1304
+ } else {
1305
+ deskChangeFullscreenZoom();
1306
+ setTimeout(deskToggleFull, 10);
1307
+ }
1308
+ }
1309
+
1310
+ function deskMenuButton(x) {
1311
+ toggleMenu(true);
1312
+ deskSendKeys(x);
1313
+ }
1314
+
1315
+
1316
+ //
1317
+ // Desktop Shortcut Keys
1318
+ //
1319
+
1320
+ function updateDeskShortcutKeys() {
1321
+ var x = ''; //'<div class="menuButton" onclick="deskMenuButton(-1)">' + "Customize" + '</div>';
1322
+ for (var i in deskKeyboardShortcuts) { x += '<div class="menuButton" onclick="deskMenuButton(' + deskKeyboardShortcuts[i] + ')">' + keyShortcutTotext(deskKeyboardShortcuts[i]) + '</div>'; }
1323
+ QH('deskButtonMenu', x);
1324
+ }
1325
+
1326
+ var keyStrings = { 8: "BackSpace", 9: "Tab", 13: "Enter", 27: "Escape", 44: "Print Screen", 45: "Insert", 46: "Del", 36: "Home", 35: "End", 33: "Page Up", 34: "Page Down", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 0: "None" }
1327
+
1328
+ function keyShortcutTotext(n) {
1329
+ var x = [];
1330
+ if (n & 0x010000) { x.push("Shift"); }
1331
+ if (n & 0x020000) { x.push("Alt"); }
1332
+ if (n & 0x080000) { x.push("Ctrl"); }
1333
+ if (n & 0x100000) { x.push("Win"); }
1334
+ n = (n & 0xFFFF);
1335
+ if ((n >= 112) && (n <= 123)) { x.push('F' + (n - 111)); } // Fx keys
1336
+ else if ((n != 0) && (keyStrings[n])) { x.push(keyStrings[n]); }
1337
+ else { if (n != 0) { x.push(String.fromCharCode(n)); } }
1338
+ return x.join(' + ');
1339
+ }
1340
+
1341
+ // Customize keyboard shortcuts
1342
+ function deskCustomizeKeys() {
1343
+ if (xxdialogMode) return;
1344
+ var x = '<div id=d2shortcuts style="width:100%;height:180px;padding:4px;overflow-y:auto;border:1px solid gray"></div><div style=width:100%;padding:5px>';
1345
+ x += '<label><input id=d1kshift type=checkbox /> ' + "Shift" + '</label><label> <input id=d1kalt type=checkbox /> ' + "Alt" + '</label><label> <input id=d1kctrl type=checkbox /> ' + "Ctrl" + '</label> <input id=d1kwin type=checkbox /> ' + "Win" + '</label>';
1346
+ x += ' <select id=d2keySelect>';
1347
+ for (var i in keyStrings) { x += '<option value=' + i + '>' + keyStrings[i] + '</option>'; }
1348
+ for (var i = 1; i <= 12; i++) { x += '<option value=' + (i + 111) + '>F' + i + '</option>'; }
1349
+ for (var i = 0; i < 10; i++) { x += '<option value=' + (i + 48) + '>' + i + '</option>'; }
1350
+ for (var i = 0; i < 26; i++) { x += '<option value=' + (i + 65) + '>' + String.fromCharCode(i + 65) + '</option>'; }
1351
+ x += '</select> <input type=button value=' + "Add" + ' onclick=addDeskCustomizeKey() /></div>';
1352
+ QH('p10dialog2', x);
1353
+ xxdialogMode = 2;
1354
+ QV('p10dialog', true);
1355
+ deskUpdateShortcutList();
1356
+ }
1357
+
1358
+ function deskCustomizeKeysEx() {
1359
+ QV('p10dialog', false);
1360
+ xxdialogMode = 0;
1361
+ //putstore('deskKeyShortcuts', deskKeyboardShortcuts.join(','));
1362
+ updateDeskShortcutKeys();
1363
+ }
1364
+
1365
+ function deskUpdateShortcutList() {
1366
+ var x = '';
1367
+ for (var i in deskKeyboardShortcuts) {
1368
+ var kt = keyShortcutTotext(deskKeyboardShortcuts[i]), orderButtons = '';
1369
+ if (i != (deskKeyboardShortcuts.length - 1)) { orderButtons += '<img width=8 height=8 style=float:right;cursor:pointer;padding:3px src="images/c2.png" onclick=deskCustomizeKeyDown(' + deskKeyboardShortcuts[i] + ')>'; }
1370
+ if (i != 0) { orderButtons += '<img width=8 height=8 style=float:right;cursor:pointer;padding:3px src="images/c3.png" onclick=deskCustomizeKeyUp(' + deskKeyboardShortcuts[i] + ')>'; }
1371
+ x += '<div style="width:100%;background-color:#AAA;border-radius:4px;margin-bottom:4px;padding:4px;text-align:left;box-sizing:border-box" value=' + deskKeyboardShortcuts[i] + '>' + kt + '<img width=10 height=10 style=float:right;cursor:pointer;padding:2px;margin-left:8px src="images/trash.png" onclick=removeDeskCustomizeKey(' + deskKeyboardShortcuts[i] + ')>' + orderButtons + '</div>';
1372
+ }
1373
+ if (x == '') { x = '<i>' + "No keyboard shortcuts defined" + '</i>'; }
1374
+ QH('d2shortcuts', x);
1375
+ }
1376
+
1377
+ function deskCustomizeKeyDown(k) {
1378
+ var i = deskKeyboardShortcuts.indexOf(k), x = deskKeyboardShortcuts[i + 1];
1379
+ deskKeyboardShortcuts[i + 1] = deskKeyboardShortcuts[i];
1380
+ deskKeyboardShortcuts[i] = x;
1381
+ deskUpdateShortcutList();
1382
+ }
1383
+
1384
+ function deskCustomizeKeyUp(k) {
1385
+ var i = deskKeyboardShortcuts.indexOf(k), x = deskKeyboardShortcuts[i];
1386
+ deskKeyboardShortcuts[i] = deskKeyboardShortcuts[i - 1];
1387
+ deskKeyboardShortcuts[i - 1] = x;
1388
+ deskUpdateShortcutList();
1389
+ }
1390
+
1391
+ function removeDeskCustomizeKey(k) {
1392
+ var na = [];
1393
+ for (var i in deskKeyboardShortcuts) { if (deskKeyboardShortcuts[i] != k) { na.push(deskKeyboardShortcuts[i]); } }
1394
+ deskKeyboardShortcuts = na;
1395
+ deskUpdateShortcutList();
1396
+ }
1397
+
1398
+ function addDeskCustomizeKey() {
1399
+ var k = parseInt(Q('d2keySelect').value);
1400
+ if (Q('d1kshift').checked) { k |= 0x010000; }
1401
+ if (Q('d1kalt').checked) { k |= 0x020000; }
1402
+ if (Q('d1kctrl').checked) { k |= 0x080000; }
1403
+ if (Q('d1kwin').checked) { k |= 0x100000; }
1404
+ if ((k > 0) && (deskKeyboardShortcuts.indexOf(k) == -1)) { deskKeyboardShortcuts.push(k); deskUpdateShortcutList(); }
1405
+ }
1406
+
1407
+ // Remote desktop special key combos for Windows
1408
+ function deskSendKeys(ks) {
1409
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
1410
+
1411
+ // Construct the key command
1412
+ if (ks == -1) { deskCustomizeKeys(); return; } // Customize
1413
+ if (ks == 0x0A002E) { desktop.m.sendcad(); return; } // CTRL-ALT-DEL
1414
+ //if ((desktop.contype == 1) && (ks == 0x10004C)) { desktop.sendCtrlMsg('{"action":"lock"}'); return; } // Lock desktop, WIN + L
1415
+
1416
+ var flags = (ks & 0xFF0000) >> 16, key = (ks & 0xFFFF), keyArray = [], keyArray2 = [];
1417
+ var amtTranslate = {
1418
+ 8: 0xff08, // BackSpace
1419
+ 9: 0xff09, // Tab
1420
+ 13: 0xff0d, // Return or Enter
1421
+ 27: 0xff1b, // Escape
1422
+ 45: 0xff63, // Insert
1423
+ 46: 0xffff, // Delete
1424
+ 36: 0xff50, // Home
1425
+ 35: 0xff57, // End
1426
+ 33: 0xff55, // Page Up
1427
+ 34: 0xff56, // Page Down
1428
+ 37: 0xff51, // Left arrow
1429
+ 38: 0xff52, // Up arrow
1430
+ 39: 0xff53, // Right arrow
1431
+ 40: 0xff54, // Down arrow
1432
+ 112: 0xffbe, // F1
1433
+ 113: 0xffbf, // F2
1434
+ 114: 0xffc0, // F3
1435
+ 115: 0xffc1, // F4
1436
+ 116: 0xffc2, // F5
1437
+ 117: 0xffc3, // F6
1438
+ 118: 0xffc4, // F7
1439
+ 119: 0xffc5, // F8
1440
+ 120: 0xffc6, // F9
1441
+ 121: 0xffc7, // F10
1442
+ 122: 0xffc8, // F11
1443
+ 123: 0xffc9 // F12
1444
+ }
1445
+
1446
+ // 0x010000 = Shift
1447
+ // 0x020000 = Left-Alt
1448
+ // 0x080000 = Ctrl
1449
+ // 0x100000 = Window
1450
+
1451
+ if (desktop.contype == 2) {
1452
+ // Intel AMT
1453
+ if (flags & 1) { keyArray.push([0xffe1, 1]); keyArray2.push([0xffe1, 0]); } // Shift
1454
+ if (flags & 2) { keyArray.push([0xffe9, 1]); keyArray2.push([0xffe9, 0]); } // Left-alt
1455
+ if (flags & 8) { keyArray.push([0xffe3, 1]); keyArray2.push([0xffe3, 0]); } // Ctrl
1456
+ if (flags & 16) { keyArray.push([0xffe7, 1]); keyArray2.push([0xffe7, 0]); } // Windows key
1457
+ if (amtTranslate[key]) { key = amtTranslate[key]; }
1458
+ if ((key >= 65) && (key <= 90)) { key += 32; }
1459
+ if (key != 0) { keyArray.push([key, 1]); keyArray2.push([key, 0]); }
1460
+ keyArray2.reverse();
1461
+ for (var i = 0; i < keyArray2.length; i++) { keyArray.push(keyArray2[i]); }
1462
+ desktop.m.sendkey(keyArray);
1463
+ } else {
1464
+ // Agent desktop
1465
+ if (flags & 1) { keyArray.push([desktop.m.KeyAction.DOWN, 16]); keyArray2.push([desktop.m.KeyAction.UP, 16]); } // Shift
1466
+ if (flags & 2) { keyArray.push([desktop.m.KeyAction.EXDOWN, 18]); keyArray2.push([desktop.m.KeyAction.EXUP, 18]); } // Left-alt
1467
+ if (flags & 8) { keyArray.push([desktop.m.KeyAction.EXDOWN, 17]); keyArray2.push([desktop.m.KeyAction.EXUP, 17]); } // Ctrl
1468
+ if (flags & 16) { keyArray.push([desktop.m.KeyAction.EXDOWN, 0x5B]); keyArray2.push([desktop.m.KeyAction.EXUP, 0x5B]); } // Windows key
1469
+ if (key != 0) { keyArray.push([desktop.m.KeyAction.DOWN, key]); keyArray2.push([desktop.m.KeyAction.UP, key]); }
1470
+ keyArray2.reverse();
1471
+ for (var i = 0; i < keyArray2.length; i++) { keyArray.push(keyArray2[i]); }
1472
+ desktop.m.SendKeyMsgKC(keyArray);
1473
+ }
1474
+ }
1475
+
1476
+
1477
+ //
1478
+ // Terminal
1479
+ //
1480
+
1481
+ function setupTerminal() {
1482
+ // Setup the terminal
1483
+ if (terminal != null) { terminal.Stop(); terminal = null; }
1484
+ updateTerminalButtons();
1485
+
1486
+ // Terminal special keys
1487
+ var x = '';
1488
+ for (var c = 1; c < 27; c++) x += '<option value=\'' + c + '\'>' + "Ctrl" + '-' + String.fromCharCode(64 + c) + ' (' + c + ')</option>';
1489
+ QH('specialkeylist', x);
1490
+ }
1491
+
1492
+ // Show and enable the right buttons
1493
+ function updateTerminalButtons() {
1494
+ var termState = ((terminal != null) && (terminal.state != 0));
1495
+
1496
+ // Show the right buttons
1497
+ QV('disconnectbutton2span', termState == true);
1498
+ QV('connectbutton2span', termState == false);
1499
+ //QV('terminalSizeDropDown', termState == false);
1500
+
1501
+ // Enable buttons
1502
+ QE('connectbutton2', true);
1503
+
1504
+ // Key buttons
1505
+ QE('ctrlcbutton', termState);
1506
+ QE('ctrlxbutton', termState);
1507
+ QE('escbutton', termState);
1508
+ QE('bsbutton', termState);
1509
+ QE('pastebutton', termState);
1510
+ QE('specialkeylist', termState);
1511
+ QE('specialkeylistinput', termState);
1512
+
1513
+ // Terminal settings
1514
+ QV('terminalSettingsButtons', (terminal) && (terminal.contype == 2));
1515
+ if (terminal) {
1516
+ Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
1517
+ Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
1518
+ Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n') ? "CR+LF" : "LF";
1519
+ }
1520
+
1521
+ // Display extra buttons on legacy terminal
1522
+ var xtermActive = true;
1523
+ QV('termarea3xdiv', xtermActive);
1524
+ QV('bsbutton', !xtermActive);
1525
+ QV('pastebutton', !xtermActive);
1526
+ QV('devListToolbarViewIcons2', xtermActive);
1527
+ QE('termSizeList', terminal == null);
1528
+ }
1529
+
1530
+ // Called when the terminal state changes
1531
+ function onTerminalStateChange(xterminal, state) {
1532
+ var xstate = state;
1533
+ if ((xstate == 3) && (xterminal.contype == 2)) { xstate++; }
1534
+ var str = StatusStrs[xstate];
1535
+ if (terminal.webRtcActive == true) { str += ", WebRTC"; }
1536
+ QH('termstatus', str);
1537
+ switch (state) {
1538
+ case 0:
1539
+ // Disconnected, clear the terminal
1540
+ QH('termtitle', '');
1541
+ QV('termRecordIcon', false);
1542
+ if (xterm == null) {
1543
+ xterminal.m.TermResetScreen();
1544
+ xterminal.m.TermDraw();
1545
+ } else {
1546
+ xterm.dispose();
1547
+ xterm = xtermfit = null;
1548
+ }
1549
+ if (terminal != null) { terminal.Stop(); terminal = null; }
1550
+ break;
1551
+ case 3:
1552
+ if (xterminal && (xterminal.serverIsRecording == true)) { QV('termRecordIcon', true); }
1553
+ terminal.startTime = new Date();
1554
+ if (updateSessionTimer == null) { updateSessionTimer = setInterval(updateSessionTime, 1000); }
1555
+ if (xterm != null) { xterm.focus(); }
1556
+ break;
1557
+ default:
1558
+ //console.log('Unhandled onTerminalStateChange state', state);
1559
+ break;
1560
+ }
1561
+ updateTerminalButtons();
1562
+ }
1563
+
1564
+ function updateSessionTime() {
1565
+ // Terminal
1566
+ var latencyStr = '', seconds = 0;
1567
+ if (terminal && terminal.startTime) {
1568
+ if (terminal.latency && (terminal.latency.current >= 0)) { latencyStr = format('{0} ms, ', terminal.latency.current); }
1569
+ seconds = Math.floor((new Date() - terminal.startTime) / 1000);
1570
+ QH('TermTimer', latencyStr + zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2));
1571
+ } else {
1572
+ QH('TermTimer', '');
1573
+ }
1574
+
1575
+ if (terminal == null) { clearInterval(updateSessionTimer); updateSessionTimer = null; }
1576
+ }
1577
+
1578
+ // DEBUG
1579
+ var autoConnectTerminalTimer = null;
1580
+ function autoConnectTerminal(e) { if (autoConnectTerminalTimer == null) { autoConnectTerminalTimer = setInterval(connectTerminal, 100); } else { clearInterval(autoConnectTerminalTimer); autoConnectTerminalTimer = null; } }
1581
+
1582
+ // Handles a tunnel to a remote shell
1583
+ function CreateRemoteTunnel(onTunnelUpdate, options) {
1584
+ var obj = { protocol: 1 };
1585
+ if ((options != null) && (typeof options.protocol == 'number')) { obj.protocol = options.protocol; }
1586
+ obj.onTunnelUpdate = onTunnelUpdate;
1587
+ obj.xxStateChange = function (state) { }
1588
+ obj.ProcessBinaryData = function (data) { obj.onTunnelUpdate(data); }
1589
+ obj.ProcessData = function (data) { obj.onTunnelUpdate(data); }
1590
+ obj.terminalEmulation = 1;
1591
+ obj.fxEmulation = 0;
1592
+ obj.lineFeed = '\r\n';
1593
+ return obj;
1594
+ }
1595
+
1596
+ function tunnelUpdate(data) { if (typeof data == 'string') { xterm.writeUtf8(data); } else { xterm.writeUtf8(new Uint8Array(data)); } }
1597
+
1598
+ // Send the new terminal size to the agent
1599
+ function xTermSendResize() {
1600
+ xtermResizeTimer = null;
1601
+ if ((xterm != null) && (terminal != null) && (terminal.sendCtrlMsg != null)) { terminal.sendCtrlMsg(JSON.stringify({ ctrlChannel: '102938', type: 'termsize', cols: xterm.cols, rows: xterm.rows })); }
1602
+ }
1603
+
1604
+ // Used to translate incoming agent console messages
1605
+ var agentConsoleMessages = ['', "Waiting for user to grant access...", "Denied", "Failed to start remote terminal session, {0} ({1})", "Timeout", "Received invalid network data"];
1606
+ function formatAgentConsoleMessage(msg, msgid, msgargs) {
1607
+ var r;
1608
+ if (msgargs == null) { msgargs = []; }
1609
+ while (msgargs.length < 3) { msgargs.push(''); } // We need to call the format function in a way that works with older browsers and minifier, can't use apply() or ...
1610
+ if (msgid && (msgid < agentConsoleMessages.length)) { r = EscapeHtml(format(agentConsoleMessages[msgid], (msgargs[0]), (msgargs[1]), (msgargs[2]))); } else { r = EscapeHtml(msg); }
1611
+ return r.split('\n').join('<br />') + '<br /><br />';
1612
+ }
1613
+
1614
+ function connectTerminal(e, contype, options) {
1615
+ p12clearConsoleMsg();
1616
+ if (!terminal) {
1617
+ // Terminal setup
1618
+ var termoptions = { protocol: ((options != null) && (typeof options.protocol == 'number')) ? options.protocol : 1 };
1619
+ if (options && options.requireLogin) { termoptions.requireLogin = true; }
1620
+ /*
1621
+ if ([1, 2, 3, 4, 21, 22].indexOf(currentNode.agent.id) == -1) {
1622
+ if (Q('termSizeList').value == 1) { termoptions.cols = 80; termoptions.rows = 25; termoptions.xterm = true; }
1623
+ else if (Q('termSizeList').value == 2) { termoptions.cols = 100; termoptions.rows = 30; termoptions.xterm = true; }
1624
+ else if (Q('termSizeList').value == 3) {
1625
+ // TODO: Try to improve terminal auto-size.
1626
+ termoptions.cols = Math.floor((Q('column_l').clientWidth - 60) / 10);
1627
+ termoptions.rows = Math.floor((Q('column_l').clientHeight - 120) / 20);
1628
+ termoptions.xterm = true;
1629
+ }
1630
+ }
1631
+ */
1632
+
1633
+ /*
1634
+ // If shift is pressed
1635
+ if ((e && (e.shiftKey == true))) {
1636
+ if (currentNode.agent.id > 4) {
1637
+ if (termoptions.protocol == 1) { termoptions.protocol = 7; } // Switch to user shell
1638
+ } else {
1639
+ if (termoptions.protocol == 1) { termoptions.protocol = 6; } // Switch to Powershell
1640
+ }
1641
+ }
1642
+ */
1643
+
1644
+ // Setup a mesh agent xterm terminal
1645
+ QV('termarea3xdiv', true);
1646
+
1647
+ // Setup the terminal with auto-fit
1648
+ if (xterm != null) { xterm.dispose(); }
1649
+ xtermfit = new FitAddon.FitAddon();
1650
+ xterm = new Terminal();
1651
+ if (xtermfit) { xterm.loadAddon(xtermfit); }
1652
+ xterm.open(Q('termarea3xdiv')); // termarea3x
1653
+ xterm.onData(function (data) { if (terminal != null) { terminal.sendText(data); } })
1654
+ if (xtermfit) { xtermfit.fit(); }
1655
+ xterm.onTitleChange(function (title) { QH('termtitle', ' - ' + EscapeHtml(title)); });
1656
+ xterm.onResize(function (size) {
1657
+ // Despam resize
1658
+ if (xtermResizeTimer) clearTimeout(xtermResizeTimer);
1659
+ xtermResizeTimer = setTimeout(xTermSendResize, 200);
1660
+ });
1661
+
1662
+ // Setup a terminal tunnel to the agent
1663
+ terminal = CreateAgentRedirect(null, CreateRemoteTunnel(tunnelUpdate, options), serverPublicNamePort, authCookie, null, domainUrl);
1664
+ terminal.debugmode = debugmode;
1665
+ terminal.m.debugmode = debugmode;
1666
+ terminal.options = { cols: xterm.cols, rows: xterm.rows };
1667
+ if (options && options.requireLogin) { terminal.options.requireLogin = true; }
1668
+ terminal.Start(null);
1669
+ terminal.onStateChanged = onTerminalStateChange;
1670
+ terminal.contype = 1;
1671
+ terminal.attemptWebRTC = false; // Never do WebRTC on terminal, because of a race condition we can't do it.
1672
+ terminal.onConsoleMessageChange = function (server, msg) {
1673
+ if (terminal.consoleMessage) {
1674
+ Q('p12TermConsoleMsg').innerHTML += formatAgentConsoleMessage(terminal.consoleMessage, terminal.consoleMessageId, terminal.consoleMessageArgs);
1675
+ QV('p12TermConsoleMsg', true);
1676
+ if (p12TermConsoleMsgTimer != null) { clearTimeout(p12TermConsoleMsgTimer); }
1677
+ if (terminal.consoleMessageTimeout) { p12TermConsoleMsgTimer = setTimeout(p12clearConsoleMsg, terminal.consoleMessageTimeout * 1000); }
1678
+ } else {
1679
+ p12clearConsoleMsg();
1680
+ }
1681
+ };
1682
+ } else {
1683
+ terminal.Stop();
1684
+ terminal = null;
1685
+ }
1686
+ Q('connectbutton2').blur(); // Deselect the connect button so the button does not get key presses.
1687
+ }
1688
+
1689
+ var terminalEmulations = ["UTF8 Terminal", "Extended ASCII", "Intel ASCII"];
1690
+ function termToggleType() {
1691
+ if (!terminal || xxdialogMode) return;
1692
+ terminal.m.terminalEmulation = (terminal.m.terminalEmulation + 1) % 3;
1693
+ Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
1694
+ Q('id_ttypebutton').blur(); // Deselect the connect button so the button does not get key presses.
1695
+ }
1696
+
1697
+ var fxEmulations = ["Intel (F10 = ESC+[OM)", "Alternate (F10 = ESC+0)", "VT100+ (F10 = ESC+[OY)"];
1698
+ function termToggleFx() {
1699
+ if (!terminal || xxdialogMode) return;
1700
+ terminal.m.fxEmulation = (terminal.m.fxEmulation + 1) % 3;
1701
+ Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
1702
+ Q('id_tfxkeysbutton').blur(); // Deselect the connect button so the button does not get key presses.
1703
+ }
1704
+
1705
+ function termToggleCr() {
1706
+ if (!terminal || xxdialogMode) return;
1707
+ if (terminal.m.lineFeed == '\n') { terminal.m.lineFeed = '\r\n'; } else { terminal.m.lineFeed = '\n'; }
1708
+ Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n') ? "CR+LF" : "LF";
1709
+ }
1710
+
1711
+ function termSendKey(key, id) {
1712
+ if (!terminal || xxdialogMode) return;
1713
+ if (xterm != null) {
1714
+ if (terminal.sendText) {
1715
+ // MeshAgent
1716
+ terminal.sendText(String.fromCharCode(key));
1717
+ } else {
1718
+ // CIRA
1719
+ terminal.send(String.fromCharCode(key));
1720
+ }
1721
+ xterm.focus();
1722
+ } else if (terminal != null) {
1723
+ terminal.m.TermSendKey(key);
1724
+ Q(id).blur(); // Deselect the connect button so the button does not get key presses.
1725
+ }
1726
+ }
1727
+
1728
+ function showTermPasteDialog() {
1729
+ if (!terminal || xxdialogMode) return;
1730
+ Q('pastebutton').blur();
1731
+ setDialogMode(2, "Paste", 3, showTermPasteDialogEx, '<textarea id=d2pasteText style="width:100%;height:184px;resize:none"></textarea>');
1732
+ Q('d2pasteText').focus();
1733
+ }
1734
+
1735
+ function showTermPasteDialogEx() {
1736
+ if (!terminal) return;
1737
+ terminal.m.TermSendKeys(Q('d2pasteText').value);
1738
+ }
1739
+
1740
+ // Send special key
1741
+ function sendSpecialKey() {
1742
+ if (xterm != null) {
1743
+ terminal.sendText(String.fromCharCode(Q('specialkeylist').value));
1744
+ xterm.focus();
1745
+ } else if (terminal != null) {
1746
+ terminal.m.TermSendKey(Q('specialkeylist').value);
1747
+ Q('specialkeylist').blur();
1748
+ Q('specialkeylistinput').blur();
1749
+ }
1750
+ }
1751
+
1752
+ function p12clearConsoleMsg() { QH('p12TermConsoleMsg', ''); QV('p12TermConsoleMsg', false); if (p12TermConsoleMsgTimer) { clearTimeout(p12TermConsoleMsgTimer); p12TermConsoleMsgTimer = null; } }
1753
+
1754
+
1755
+
1756
+ //
1757
+ // Files
1758
+ //
1759
+
1760
+ function setupFiles() {
1761
+ // Setup the files tab
1762
+ if (files != null) { files.Stop(); files = null; }
1763
+ }
1764
+
1765
+ function onFilesStateChange(xfiles, state) {
1766
+ p13Connect.value = (state == 0) ? "Connect" : "Disconnect";
1767
+ var str = StatusStrs[state];
1768
+ if (files.webRtcActive == true) { str += ", WebRTC"; }
1769
+ Q('p13Status').textContent = str;
1770
+ switch (state) {
1771
+ case 0:
1772
+ // Disconnected, clear the files
1773
+ QH('p13files', '');
1774
+ p13filetree = null;
1775
+ p13filetreelocation = [];
1776
+ QH('p13currentpath', '');
1777
+ QE('p13FolderUp', false);
1778
+ QV('filesRecordIcon', false);
1779
+ p13setActions();
1780
+ if (files != null) { files.Stop(); files = null; }
1781
+ if (xxdialogTag == 'fileMsgDialog') { setDialogMode(0); }
1782
+ break;
1783
+ case 3:
1784
+ p13targetpath = '';
1785
+ if (files) {
1786
+ files.sendText({ action: 'ls', reqid: 1, path: '' });
1787
+ if (files.serverIsRecording == true) { QV('filesRecordIcon', true); }
1788
+ }
1789
+ break;
1790
+ default:
1791
+ //console.log('Unknown onFilesStateChange state', state);
1792
+ break;
1793
+ }
1794
+ }
1795
+
1796
+ function CreateRemoteFiles(onFileUpdate) {
1797
+ var obj = { protocol: 5 };
1798
+ obj.onFileUpdate = onFileUpdate;
1799
+ obj.xxStateChange = function (state) { }
1800
+ obj.ProcessData = function (data) { obj.onFileUpdate(data); }
1801
+ return obj;
1802
+ }
1803
+
1804
+ function connectFiles(e) {
1805
+ p13clearConsoleMsg();
1806
+ if (!files) {
1807
+ // Setup a mesh agent files
1808
+ files = CreateAgentRedirect(null, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, null, domainUrl);
1809
+ files.attemptWebRTC = attemptWebRTC;
1810
+ files.onStateChanged = onFilesStateChange;
1811
+ files.onConsoleMessageChange = function () {
1812
+ if (files.consoleMessage) {
1813
+ Q('p13FilesConsoleMsg').innerHTML += formatAgentConsoleMessage(files.consoleMessage, files.consoleMessageId, files.consoleMessageArgs);
1814
+ QV('p13FilesConsoleMsg', true);
1815
+ if (p13FilesConsoleMsgTimer != null) { clearTimeout(p13FilesConsoleMsgTimer); }
1816
+ if (files.consoleMessageTimeout) { p13FilesConsoleMsgTimer = setTimeout(p13clearConsoleMsg, files.consoleMessageTimeout * 1000); }
1817
+ } else {
1818
+ p13clearConsoleMsg();
1819
+ }
1820
+ }
1821
+ files.Start(null);
1822
+ } else {
1823
+ //QH('Term', '');
1824
+ files.Stop();
1825
+ files = null;
1826
+ }
1827
+ p13clipboard = p13clipboardFolder = null;
1828
+ p13clipboardCut = 0;
1829
+ p13updateClipview();
1830
+ }
1831
+
1832
+ var p13filetree = null;
1833
+ var p13targetpath = null;
1834
+ var p13filetreelocation = [];
1835
+
1836
+ function p13fileOperationDialogEx(b) { if ((b == 0) && (files != null)) { files.sendText({ action: 'cancel' }); } }
1837
+
1838
+ function p13gotFiles(data) {
1839
+ if ((data.length > 0) && (data.charCodeAt(0) != 123)) { p13gotDownloadBinaryData(data); return; } // This is ok because 4 first bytes is a control value.
1840
+ //console.log('p13gotFiles', data);
1841
+ try { data = JSON.parse(decode_utf8(data)); } catch (ex) { data = JSON.parse(data); }
1842
+ if (data.action == 'download') { p13gotDownloadCommand(data); return; }
1843
+
1844
+ // Find file result
1845
+ if (data.action == 'findfile') {
1846
+ if (xxdialogTag == data.reqid) {
1847
+ if (data.r == null) {
1848
+ QE('d2findFilter', true);
1849
+ QE('filefind_dlgOkButton', true);
1850
+ xxdialogTag = null;
1851
+ if (Q('d2findResults').innerHTML == '') { QH('d2findResults', '<div style=text-align:center;margin:10px><i>' + "No files found" + '</i></div>'); }
1852
+ } else {
1853
+ QA('d2findResults', '<div style=white-space:nowrap>' + EscapeHtml(data.r) + '</div>');
1854
+ }
1855
+ }
1856
+ return;
1857
+ }
1858
+
1859
+ // Process file upload commands
1860
+ if ((data.action != null) && (data.action.startsWith('upload'))) { p13gotUploadData(data); return; }
1861
+
1862
+ // Display a dialog message
1863
+ if (data.action == 'dialogmessage') {
1864
+ if ((data.msg == null) && (xxdialogTag == 'fileMsgDialog')) {
1865
+ setDialogMode(0); // Close the dialog box
1866
+ } else if ((data.msg == 'zipping') && ((!xxdialogMode) || (xxdialogTag == 'fileMsgDialog'))) {
1867
+ // Show the dialog box message
1868
+ setDialogMode(2, "File Operation", 10, p13fileOperationDialogEx, '<div style=margin:10px>' + "Compressing files..." + '<div>', 'fileMsgDialog');
1869
+ } else if ((data.msg == 'zippingFile') && ((!xxdialogMode) || (xxdialogTag == 'fileMsgDialog'))) {
1870
+ // Show the dialog box message
1871
+ setDialogMode(2, "File Operation", 10, p13fileOperationDialogEx, '<div style=margin:10px>' + EscapeHtml(data.file) + '<div><br /><progress value=' + EscapeHtml(data.progress) + ' style=width:100% max=100 />', 'fileMsgDialog');
1872
+ }
1873
+ return;
1874
+ }
1875
+
1876
+ // Refresh file folder
1877
+ if (data.action == 'refresh') { p13folderup(9999); return; }
1878
+
1879
+ if (data.path != null) {
1880
+ data.path = data.path.replace(/\//g, '\\');
1881
+ if ((p13filetree != null) && (data.path == p13filetree.path)) {
1882
+ // This is an update to the same folder
1883
+ var checkedNames = p13getCheckedNames();
1884
+ p13filetree = data;
1885
+ p13updateFiles(checkedNames);
1886
+ } else {
1887
+ // Make both paths use the same seperator not start with /
1888
+ var x1 = data.path.replace(/\//g, '\\'), x2 = p13targetpath.replace(/\//g, '\\');
1889
+ while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
1890
+ while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
1891
+ if ((x1 == x2) || ((data.path == '\\') && (p13targetpath == ''))) {
1892
+ // This is a different folder
1893
+ p13filetree = data;
1894
+ p13updateFiles();
1895
+ }
1896
+ }
1897
+ }
1898
+ }
1899
+
1900
+ function p13getCheckedNames() {
1901
+ // Save all existing checked boxes
1902
+ var checkedNames = [], checkboxes = document.getElementsByName('fd');
1903
+ for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedNames.push(p13filetree.dir[checkboxes[i].value].n) }; }
1904
+ return checkedNames;
1905
+ }
1906
+
1907
+ function p13updateFiles(checkedNames) {
1908
+ var html1 = '', html2 = '', displayPath = '<a href=# style=cursor:pointer onclick="return p13folderup(0)">' + "Root" + '</a>', fullPath = 'Root';
1909
+
1910
+ // Work on parsing the file path
1911
+ var x = p13filetree.path.split('\\');
1912
+ p13filetreelocation = [];
1913
+ for (var i in x) { if (x[i] != '') { p13filetreelocation.push(x[i]); } } // Remove empty spaces
1914
+ for (var i in p13filetreelocation) { displayPath += ' / <a href=# style=cursor:pointer onclick="return p13folderup(' + (parseInt(i) + 1) + ')">' + EscapeHtml(p13filetreelocation[i]) + '</a>' } // Setup the path we display
1915
+ var newlinkpath = p13filetreelocation.join('/');
1916
+
1917
+ // Sort the files
1918
+ var filetreexx = p13sort_files(p13filetree.dir);
1919
+
1920
+ // Display all files and folders at this location
1921
+ for (var i in filetreexx) {
1922
+ // Figure out the name and shortname
1923
+ var f = filetreexx[i], name = f.n, shortname;
1924
+ shortname = name;
1925
+ if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + ("..." + '</span>'); } else { shortname = EscapeHtml(name); }
1926
+ name = EscapeHtml(name);
1927
+
1928
+ // Figure out the date
1929
+ var fdatestr = '';
1930
+ if (f.d != null) {
1931
+ var fdate = new Date(f.d);
1932
+ if (typeof f.d == 'number') { fdate = new Date(f.d * 1000); }
1933
+ var fdatestr = printDateTime(fdate) + ' ';
1934
+ }
1935
+
1936
+ // Figure out the size
1937
+ var fsize = '';
1938
+ if (f.s != null) { fsize = getFileSizeStr(f.s); }
1939
+
1940
+ var h = '';
1941
+ if (f.t < 3) {
1942
+ var right = '', title = '';
1943
+ h = '<div class=filelist file=999><input file=999 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'> <span style=float:right title="' + title + '">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p13folderset("' + encodeURIComponentEx(f.nx) + '")></div><a href=# style=cursor:pointer onclick=\'return p13folderset("' + encodeURIComponentEx(f.nx) + '")\'>' + shortname + '</a></span></div>';
1944
+ } else {
1945
+ var link = shortname;
1946
+ if (f.s > 0) {
1947
+ // Local link
1948
+ //link = '<a href=# style=cursor:pointer onclick="return p13downloadfile(\'' + encodeURIComponentEx(newlinkpath + '/' + name) + '\',\'' + encodeURIComponentEx(name) + '\',' + f.s + ')">' + shortname + '</a>';
1949
+ // Server link
1950
+ //link = '<a href="devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '" download="' + name + '" style=cursor:pointer>' + shortname + '</a>';
1951
+ // Server link
1952
+ //link = '<a onclick=downloadFile("devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '","' + encodeURIComponentEx(name) + '") style=cursor:pointer>' + shortname + '</a>';
1953
+ link = '<a onclick=downloadFile("devicefile.ashx?c=' + authCookie + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '","' + encodeURIComponentEx(name) + '") style=cursor:pointer>' + shortname + '</a>';
1954
+ }
1955
+ h = '<div id=fileEntry cmenu=filesContextMenu fileIndex=' + i + ' class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'> <span class=fsize>' + fdatestr + '</span><span style=float:right>' + EscapeHtml(fsize) + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
1956
+ }
1957
+
1958
+ if (f.t < 3) { html1 += h; } else { html2 += h; }
1959
+ }
1960
+
1961
+ // Display the files and path
1962
+ QH('p13files', html1 + html2);
1963
+ QH('p13currentpath', displayPath);
1964
+ QE('p13FolderUp', p13filetreelocation.length != 0);
1965
+
1966
+ // Re-check all boxes if needed using names
1967
+ if (checkedNames != null) { var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkedNames.indexOf(p13filetree.dir[checkboxes[i].value].n) >= 0) { checkboxes[i].checked = true; } } }
1968
+
1969
+ // Update the actions buttons
1970
+ p13setActions();
1971
+ }
1972
+
1973
+ function p13folderset(x) {
1974
+ p13targetpath = joinPaths(p13filetree.path, p13filetree.dir[x].n).split('\\').join('/');
1975
+ files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
1976
+ }
1977
+
1978
+ function p13folderup(x) {
1979
+ if (x == null) { p13filetreelocation.pop(); } else { while (p13filetreelocation.length > x) { p13filetreelocation.pop(); } }
1980
+ p13targetpath = p13filetreelocation.join('/');
1981
+ files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
1982
+ return false;
1983
+ }
1984
+
1985
+ function p13findfile() {
1986
+ if (xxdialogMode) return;
1987
+ var x = addHtmlValue("Filter", '<input id=d2findFilter style="width:230px" onkeyup=p13findfileValidate() onkeydown=p13findfileDown(event) placeholder="*.txt"></input>');
1988
+ x += '<div id=d2findResults style="width:100%;height:184px;background-color:white;border:1px solid black;padding:3px;overflow:scroll;margin-top:8px"></div>';
1989
+ x += '<div style=margin-top:8px><input id=filefind_dlgCancelButton type=button value=' + "Close" + ' style=float:right;width:80px;margin-left:5px onclick=p13findfileCancel()>';
1990
+ x += '<input id=filefind_dlgOkButton type=submit value=' + "Search" + ' style=float:right;width:80px onclick=p13findfileEx()><br /><br /></div>';
1991
+ setDialogMode(2, "Find Files", 0, null, x);
1992
+ p13findfileValidate();
1993
+ Q('d2findFilter').focus();
1994
+ }
1995
+
1996
+ function p13findfileDown(e) { if (e.code == "Enter") { p13findfileEx(); } }
1997
+ function p13findfileValidate() { QE('filefind_dlgOkButton', Q('d2findFilter').value.length > 0); }
1998
+ function p13findfileCancel() { if (xxdialogTag != null) { files.sendText({ action: 'cancelfindfile', reqid: xxdialogTag }); } dialogclose(0) }
1999
+
2000
+ function p13findfileEx(b, t) {
2001
+ if (Q('d2findFilter').value.length == 0) return;
2002
+ var winagent = true;//((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
2003
+ var slash = winagent ? '\\' : '/';
2004
+ var path = p13filetreelocation.join(slash) + slash;
2005
+ if (!winagent) { path = slash + path; }
2006
+ xxdialogTag = 'find:' + Math.random();
2007
+ files.sendText({ action: 'findfile', reqid: xxdialogTag, path: path, filter: Q('d2findFilter').value });
2008
+ QH('d2findResults', '');
2009
+ QE('d2findFilter', false);
2010
+ QE('filefind_dlgOkButton', false);
2011
+ }
2012
+
2013
+ var p13sortorder;
2014
+ function p13sort_filename(a, b) { if (a.ln > b.ln) return (1 * p13sortorder); if (a.ln < b.ln) return (-1 * p13sortorder); return 0; }
2015
+ function p13sort_timestamp(a, b) { if (a.d > b.d) return (1 * p13sortorder); if (a.d < b.d) return (-1 * p13sortorder); return 0; }
2016
+ function p13sort_bysize(a, b) { if (a.s == b.s) return p13sort_filename(a, b); return (((a.s - b.s)) * p13sortorder); }
2017
+
2018
+ function p13sort_files(files) {
2019
+ var r = [], sortselection = Q('p13sortdropdown').value;
2020
+ for (var i in files) { files[i].nx = i; if (files[i].s == null) { files[i].s = 0; } if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
2021
+ p13sortorder = 1;
2022
+ if (sortselection > 3) { p13sortorder = -1; sortselection -= 3; }
2023
+ if (sortselection == 1) { r.sort(p13sort_filename); }
2024
+ else if (sortselection == 2) { r.sort(p13sort_bysize); }
2025
+ else if (sortselection == 3) { r.sort(p13sort_timestamp); }
2026
+ return r;
2027
+ }
2028
+
2029
+ function p13setActions() {
2030
+ var advancedFeatures = true; //(currentNode.agent.id != 14); // Reduct file feature on some devices.
2031
+ if (p13filetree == null) {
2032
+ QE('p13DeleteFileButton', false);
2033
+ QE('p13NewFolderButton', false);
2034
+ QE('p13UploadButton', false);
2035
+ QE('p13RenameFileButton', false);
2036
+ QE('p13ViewFileButton', false);
2037
+ QE('p13SelectAllButton', false);
2038
+ Q('p13SelectAllButton').value = "Select All";
2039
+ QE('p13RefreshButton', false);
2040
+ QE('p13FindButton', false);
2041
+ QE('p13CutButton', false);
2042
+ QE('p13CopyButton', false);
2043
+ QE('p13ZipButton', false);
2044
+ QE('p13PasteButton', false);
2045
+ } else {
2046
+ var cc = p13getFileSelCount(), tc = p13getFileCount(), sfc = p13getFileSelCount(false); // In order: number of entires selected, number of total entries, number of selected entires that are files (not folders)
2047
+ var winAgent = true; //((currentNode.agent.id > 0) && (currentNode.agent.id < 5)) || (currentNode.agent.id == 14);
2048
+ QE('p13DeleteFileButton', (cc > 0) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2049
+ QE('p13NewFolderButton', advancedFeatures && ((p13filetreelocation.length > 0) || (winAgent == false)));
2050
+ QE('p13UploadButton', ((p13filetreelocation.length > 0) || (winAgent == false) /*|| (currentNode.agent.id == 14)*/));
2051
+ QE('p13RenameFileButton', advancedFeatures && (cc == 1) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2052
+ QE('p13ViewFileButton', advancedFeatures && (cc == 1) && (sfc == 1) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2053
+ QE('p13SelectAllButton', tc > 0);
2054
+ Q('p13SelectAllButton').value = (cc > 0 ? "Select None" : "Select All");
2055
+ QE('p13RefreshButton', true);
2056
+ QE('p13FindButton', advancedFeatures && ((p13filetreelocation.length > 0) || (winAgent == false)));
2057
+ QE('p13CutButton', advancedFeatures && (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2058
+ QE('p13CopyButton', advancedFeatures && (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2059
+ QE('p13ZipButton', advancedFeatures && (cc > 0) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2060
+ QE('p13PasteButton', advancedFeatures && ((p13filetreelocation.length > 0) || (winAgent == false)) && ((p13clipboard != null) && (p13clipboard.length > 0)));
2061
+ }
2062
+ }
2063
+
2064
+ function p13getFileSelCount(includeDirs) { var cc = 0; var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == '3'))) cc++; } return cc; }
2065
+ function p13getFileSelDirCount() { var cc = 0, checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '999')) cc++; } return cc; }
2066
+ function p13getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fd'); return checkboxes.length; }
2067
+ function p13selectallfile() { var nv = (p13getFileSelCount() == 0), checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p13setActions(); }
2068
+ function p13createfolder() { setDialogMode(2, "New Folder", 3, p13createfolderEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% />'); focusTextBox('p13renameinput'); p13fileNameCheck(); }
2069
+ function p13createfolderEx() { files.sendText({ action: 'mkdir', reqid: 1, path: p13filetreelocation.join('/') + '/' + Q('p13renameinput').value }); p13folderup(999); }
2070
+ function p13deletefile() { var cc = p13getFileSelCount(), rec = (p13getFileSelDirCount() > 0) ? '<br /><br /><label><input type=checkbox id=p13recdeleteinput>' + "Recursive delete" + '</label><br>' : '<input type=checkbox id=p13recdeleteinput style=\'display:none\'>'; setDialogMode(2, "Delete", 3, p13deletefileEx, (cc > 1) ? (format("Delete {0} selected items?", cc) + rec) : ("Delete selected item?" + rec)); }
2071
+ function p13deletefileEx() { var delfiles = [], checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { delfiles.push(p13filetree.dir[checkboxes[i].value].n); } } files.sendText({ action: 'rm', reqid: 1, path: p13filetreelocation.join('/'), delfiles: delfiles, rec: Q('p13recdeleteinput').checked }); p13folderup(999); }
2072
+ function p13renamefile() { var renamefile, checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { renamefile = p13filetree.dir[checkboxes[i].value].n; } } setDialogMode(2, "Rename", 3, p13renamefileEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'rename', path: p13filetreelocation.join('/'), oldname: renamefile }); focusTextBox('p13renameinput'); p13fileNameCheck(); }
2073
+ function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.sendText(t); p13folderup(999); }
2074
+ function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); } }
2075
+ function p13uploadFile() { setDialogMode(2, "Upload File", 3, p13uploadFileEx, '<input type=file name=files id=p13uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />'); updateUploadDialogOk('p13uploadinput'); }
2076
+ function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q('p13uploadinput').files.length > 0); }
2077
+ function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
2078
+ function p13viewfile() {
2079
+ var checkboxes = document.getElementsByName('fd');
2080
+ for (var i = 0; i < checkboxes.length; i++) {
2081
+ if (checkboxes[i].checked) {
2082
+ if (p13filetree.dir[checkboxes[i].value].s <= 204800) {
2083
+ p13downloadfile(encodeURIComponentEx(p13filetreelocation.join('/') + '/' + p13filetree.dir[checkboxes[i].value].n), encodeURIComponentEx(p13filetree.dir[checkboxes[i].value].n), p13filetree.dir[checkboxes[i].value].s, 'viewer');
2084
+ } else { messagebox("File Editor", "Only files less than 200k can be edited."); }
2085
+ break;
2086
+ }
2087
+ }
2088
+ }
2089
+
2090
+ function p13zipFiles() {
2091
+ var inputFiles = [], checkboxes = document.getElementsByName('fd');
2092
+ for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { inputFiles.push(p13filetree.dir[checkboxes[i].value].n); } }
2093
+ setDialogMode(2, "Zip Filename", 3, p13zipFilesEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% value="" />', { action: 'zip', path: p13filetreelocation.join('/'), files: inputFiles });
2094
+ focusTextBox('p13renameinput');
2095
+ p13fileNameCheck();
2096
+ }
2097
+
2098
+ function p13zipFilesEx(b, tag) {
2099
+ tag.output = Q('p13renameinput').value;
2100
+ if (!tag.output.toLowerCase().endsWith('.zip')) { tag.output += '.zip'; }
2101
+ files.sendText(tag);
2102
+ }
2103
+
2104
+ var p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0;
2105
+ function p13copyFile(cut) { var checkboxes = document.getElementsByName('fd'); p13clipboard = []; p13clipboardCut = cut, p13clipboardFolder = p13targetpath; for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p13clipboard.push(p13filetree.dir[checkboxes[i].value].n); } } p13updateClipview(); }
2106
+ function p13pasteFile() {
2107
+ var x = '';
2108
+ if ((p13clipboard != null) && (p13clipboard.length > 0)) {
2109
+ if (p13clipboardCut == 0) {
2110
+ if (p13clipboard.length > 1) { x = format("Confirm copy of {0} entries to this location?", p13clipboard.length); } else { x = format("Confirm copy of 1 entrie to this location?"); }
2111
+ } else {
2112
+ if (p13clipboard.length > 1) { x = format("Confirm move of {0} entries to this location?", p13clipboard.length); } else { x = format("Confirm move of 1 entrie to this location?"); }
2113
+ }
2114
+ }
2115
+ setDialogMode(2, "Paste", 3, p13pasteFileEx, x);
2116
+ }
2117
+ function p13pasteFileEx() { files.sendText({ action: (p13clipboardCut == 0 ? 'copy' : 'move'), reqid: 1, scpath: p13clipboardFolder, dspath: p13targetpath, names: p13clipboard }); p13folderup(999); if (p13clipboardCut == 1) { p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0; p13updateClipview(); } }
2118
+ function p13updateClipview() {
2119
+ var x = '';
2120
+ if ((p13clipboard != null) && (p13clipboard.length > 0)) {
2121
+ if (p13clipboardCut == 0) {
2122
+ if (p13clipboard.length > 1) {
2123
+ x = format("Holding {0} entries for copy" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "Clear" + '</a>.', p13clipboard.length);
2124
+ } else {
2125
+ x = format("Holding 1 entrie for copy" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "Clear" + '</a>.');
2126
+ }
2127
+ } else {
2128
+ if (p13clipboard.length > 1) {
2129
+ x = format("Holding {0} entries for move" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "Clear" + '</a>.', p13clipboard.length);
2130
+ } else {
2131
+ x = format("Holding 1 entrie for move" + ', <a href=# onclick="return p13clearClip()" style=cursor:pointer>' + "Clear" + '</a>.');
2132
+ }
2133
+ }
2134
+ }
2135
+ QH('p13bottomstatus', x);
2136
+ p13setActions();
2137
+ }
2138
+ function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); return false; }
2139
+
2140
+ function p13fileDragDrop(e) {
2141
+ haltEvent(e);
2142
+ QV('p13bigfail', false);
2143
+ QV('p13bigok', false);
2144
+ if ((e.dataTransfer == null) || (e.dataTransfer.files.length == 0) || (p13filetree == null)) return;
2145
+
2146
+ // Check if these are files we can upload, remove all folders.
2147
+ var files = [];
2148
+ for (var i in e.dataTransfer.files) { if ((e.dataTransfer.files[i].size != null) && (e.dataTransfer.files[i].size != 0)) { files.push(e.dataTransfer.files[i]); } }
2149
+ if (files.length == 0) return;
2150
+
2151
+ p13doUploadFiles(files);
2152
+ }
2153
+
2154
+ var p13dragtimer = null;
2155
+ function p13fileDragOver(e) {
2156
+ haltEvent(e);
2157
+ if (p13dragtimer != null) { clearTimeout(p13dragtimer); p13dragtimer = null; }
2158
+ var ac = (p13filetree != null); // Set to true if we can accept the file
2159
+ QV('p13bigok', ac);
2160
+ QV('p13bigfail', !ac);
2161
+ }
2162
+
2163
+ function p13fileDragLeave(e) {
2164
+ haltEvent(e);
2165
+ if (e.target.id != 'p13filetable') {
2166
+ QV('p13bigfail', false);
2167
+ QV('p13bigok', false);
2168
+ } else {
2169
+ p13dragtimer = setTimeout(function () { QV('p13bigfail', false); QV('p13bigok', false); p13dragtimer = null; }, 10);
2170
+ }
2171
+ }
2172
+
2173
+ //
2174
+ // FILES DOWNLOAD
2175
+ //
2176
+
2177
+ var gdownloadFile; // Global state for file download
2178
+
2179
+ // Called by the html page to start a download, arguments are: path, file name and file size.
2180
+ function p13downloadfile(x, y, z, tag) {
2181
+ if (xxdialogMode || !files) return;
2182
+ gdownloadFile = { path: decodeURIComponent(x), file: decodeURIComponent(y), size: z, tsize: 0, data: '', state: 0, id: Math.random(), tag: tag }
2183
+ //console.log('p13downloadFileCancel', gdownloadFile);
2184
+ files.sendText({ action: 'download', sub: 'start', id: gdownloadFile.id, path: gdownloadFile.path });
2185
+ setDialogMode(2, "Download File", 10, p13downloadFileCancel, '<div>' + gdownloadFile.file + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
2186
+ }
2187
+
2188
+ // Called by the html page to cancel the download
2189
+ function p13downloadFileCancel() { setDialogMode(0); files.sendText({ action: 'download', sub: 'cancel', id: gdownloadFile.id }); gdownloadFile = null; }
2190
+
2191
+ // Called by the transport when download control command is received
2192
+ function p13gotDownloadCommand(cmd) {
2193
+ //console.log('p13gotDownloadCommand', cmd);
2194
+ if ((gdownloadFile == null) || (cmd.id != gdownloadFile.id)) return;
2195
+ if (cmd.sub == 'start') { gdownloadFile.state = 1; files.sendText({ action: 'download', sub: 'startack', id: gdownloadFile.id }); }
2196
+ else if (cmd.sub == 'cancel') { gdownloadFile = null; setDialogMode(0); }
2197
+ }
2198
+
2199
+ // Called by the transport when binary data is received
2200
+ function p13gotDownloadBinaryData(data) {
2201
+ if (!gdownloadFile || gdownloadFile.state == 0) return;
2202
+ if (data.length > 4) {
2203
+ gdownloadFile.tsize += (data.length - 4); // Add to the total bytes received
2204
+ gdownloadFile.data += data.substring(4); // Append the data
2205
+ Q('d2progressBar').value = gdownloadFile.tsize; // Change the progress bar
2206
+ }
2207
+ if ((ReadInt(data, 0) & 1) != 0) { // Check end flag
2208
+ if (gdownloadFile.tag == 'viewer') {
2209
+ // View the file in the dialog box
2210
+ setDialogMode(4, EscapeHtml(gdownloadFile.file), 3, p13editSaveBack, null, gdownloadFile.file);
2211
+ QS('dialog').width = 'auto';
2212
+ QS('dialog').bottom = '80px';
2213
+ QS('dialog').top = QS('dialog').left = QS('dialog').right = '100px';
2214
+ Q('d4editorarea').value = gdownloadFile.data;
2215
+ gdownloadFile = null;
2216
+ } else {
2217
+ // Save the file to disk
2218
+ saveAs(data2blob(gdownloadFile.data), gdownloadFile.file); gdownloadFile = null; setDialogMode(0); // Save the file
2219
+ }
2220
+ } else {
2221
+ files.sendText({ action: 'download', sub: 'ack', id: gdownloadFile.id }); // Send the ACK
2222
+ }
2223
+ }
2224
+
2225
+ var d4EditWrapVal = 0;
2226
+ var d4EditSizeVal = 0;
2227
+ function d4ToggleWrap(update) {
2228
+ if (!update) { d4EditWrapVal = ++d4EditWrapVal % 2; }
2229
+ Q('d4WrapButton').value = ["Wrap: ON", "Wrap: OFF"][d4EditWrapVal];
2230
+ QS('d4editorarea').overflow = (d4EditWrapVal == 0) ? 'auto' : 'scroll';
2231
+ QS('d4editorarea')['white-space'] = (d4EditWrapVal == 0) ? null : 'pre';
2232
+ putstore('editorWrap', d4EditWrapVal);
2233
+ }
2234
+
2235
+ function d4ToggleSize(update) {
2236
+ if (!update) { d4EditSizeVal = ++d4EditSizeVal % 4; }
2237
+ QS('d4editorarea')['font-size'] = ['100%', '125%', '150%', '200%'][d4EditSizeVal];
2238
+ Q('d4SizeButton').value = ["Size: 100%", "Size: 125%", "Size: 150%", "Size: 200%"][d4EditSizeVal];
2239
+ putstore('editorSize', d4EditSizeVal);
2240
+ }
2241
+
2242
+ function p13editSaveBack(b, tag) {
2243
+ var data = new TextEncoder().encode(Q('d4editorarea').value);
2244
+ p13uploadFileContinue(1, [{ name: tag, size: data.byteLength, type: 'text/plain', xdata: data }]);
2245
+ }
2246
+
2247
+ //
2248
+ // FILES UPLOAD
2249
+ //
2250
+
2251
+ var uploadFile;
2252
+ function p13doUploadFiles(files) {
2253
+ if (xxdialogMode) return;
2254
+
2255
+ // Check if we are going to overwrite any files
2256
+ var winAgent = true;//((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
2257
+ var targetFiles = [], overWriteCount = 0;
2258
+ for (var i in p13filetree.dir) { if (winAgent) { targetFiles.push(p13filetree.dir[i].n.toLowerCase()); } else { targetFiles.push(p13filetree.dir[i].n); } }
2259
+ for (var i = 0; i < files.length; i++) {
2260
+ if (winAgent) {
2261
+ if (targetFiles.indexOf(files[i].name.toLowerCase()) >= 0) { overWriteCount++; }
2262
+ } else {
2263
+ if (targetFiles.indexOf(files[i].name) >= 0) { overWriteCount++; }
2264
+ }
2265
+ }
2266
+
2267
+ if (overWriteCount == 0) {
2268
+ // If no overwrite, go ahead with upload
2269
+ p13uploadFileContinue(1, files);
2270
+ } else {
2271
+ // Otherwise, prompt for confirmation
2272
+ setDialogMode(2, "Upload File", 3, p13uploadFileContinue, format((overWriteCount == 1) ? "Upload will overwrite 1 file. Continue?" : "Upload will overwrite {0} files. Continue?", overWriteCount), files);
2273
+ }
2274
+ }
2275
+
2276
+ function p13uploadFileContinue(b, files) {
2277
+ uploadFile = {};
2278
+ uploadFile.xpath = p13filetreelocation.join('/');
2279
+ uploadFile.xfiles = files;
2280
+ uploadFile.xfilePtr = -1;
2281
+ setDialogMode(2, "Upload File", 10, p13uploadFileCancel, '<div id=p13dfileName>' + "Connecting..." + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=0 />');
2282
+ p13uploadNextFile();
2283
+ }
2284
+
2285
+ // Perform SHA-384 hashing
2286
+ const byteToHex = [];
2287
+ for (var n = 0; n <= 0xff; ++n) { var hexOctet = n.toString(16).padStart(2, '0'); byteToHex.push(hexOctet); }
2288
+ function arrayBufferToHex(arrayBuffer) { return Array.prototype.map.call(new Uint8Array(arrayBuffer), n => byteToHex[n]).join(''); }
2289
+ function performHash(data, f) { window.crypto.subtle.digest('SHA-384', data).then(function (v) { f(arrayBufferToHex(v)); }, function () { f(null); }); }
2290
+
2291
+ // Push the next file
2292
+ function p13uploadNextFile() {
2293
+ uploadFile.xfilePtr++;
2294
+ if (uploadFile.xfiles.length > uploadFile.xfilePtr) {
2295
+ uploadFile.xptr = 0;
2296
+ var file = uploadFile.xfiles[uploadFile.xfilePtr];
2297
+ QH('p13dfileName', file.name);
2298
+ Q('d2progressBar').max = file.size;
2299
+ Q('d2progressBar').value = 0;
2300
+ if (file.xdata == null) {
2301
+ // Load the data
2302
+ uploadFile.xreader = new FileReader();
2303
+ uploadFile.xreader.onload = function () {
2304
+ uploadFile.xdata = uploadFile.xreader.result;
2305
+
2306
+ // If the remote file already exists and is smaller then our file, see if we can resume the trasfer
2307
+ var f = null;
2308
+ for (var i in p13filetree.dir) { if (p13filetree.dir[i].n == file.name) { f = p13filetree.dir[i]; } }
2309
+ if ((f != null) && (f.s <= uploadFile.xreader.result.byteLength)) {
2310
+ performHash(uploadFile.xreader.result.slice(0, f.s), function (hash) {
2311
+ files.sendText(JSON.stringify({ action: 'uploadhash', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, tag: { h: hash.toUpperCase(), s: f.s, skip: f.s == uploadFile.xreader.result.byteLength } }));
2312
+ });
2313
+ } else {
2314
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
2315
+ }
2316
+ };
2317
+ uploadFile.xreader.readAsArrayBuffer(file);
2318
+ } else {
2319
+ // Data already loaded
2320
+ uploadFile.xdata = file.xdata;
2321
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
2322
+ }
2323
+ } else {
2324
+ p13uploadFileTransferDone();
2325
+ }
2326
+ }
2327
+
2328
+ // Used to cancel the entire transfer.
2329
+ function p13uploadFileCancel(button, tag) {
2330
+ if (uploadFile != null) { files.sendText(JSON.stringify({ action: 'uploadcancel', reqid: uploadFile.xfilePtr })); uploadFile = null; }
2331
+ p13uploadFileTransferDone();
2332
+ }
2333
+
2334
+ // Used to cancel the entire transfer.
2335
+ function p13uploadFileTransferDone() {
2336
+ uploadFile = null; // No more files to upload, clean up.
2337
+ setDialogMode(0); // Close the dialog box
2338
+ p13folderup(9999); // Refresh the current folder
2339
+ }
2340
+
2341
+ // Receive upload ack from the mesh agent, use this to keep sending more data
2342
+ function p13gotUploadData(cmd) {
2343
+ if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
2344
+ switch (cmd.action) {
2345
+ case 'uploadstart': { p13uploadNextPart(false); for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } break; } // Send 8 more blocks of 16k to fill the websocket.
2346
+ case 'uploadack': { p13uploadNextPart(false); break; }
2347
+ case 'uploaddone': { if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadNextFile(); } else { p13uploadFileTransferDone(); } break; }
2348
+ case 'uploaderror': { p13uploadFileCancel(); break; }
2349
+ case 'uploadhash': {
2350
+ var file = uploadFile.xfiles[uploadFile.xfilePtr];
2351
+ if (file) {
2352
+ if (cmd.tag.h === cmd.hash) {
2353
+ if (cmd.tag.skip) {
2354
+ p13uploadNextFile();
2355
+ } else {
2356
+ uploadFile.xptr = cmd.tag.s;
2357
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength, append: true }));
2358
+ }
2359
+ } else {
2360
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength, append: false }));
2361
+ }
2362
+ }
2363
+ break;
2364
+ }
2365
+ }
2366
+ }
2367
+
2368
+ // 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.
2369
+ function p13uploadNextPart(dataPriming) {
2370
+ var data = uploadFile.xdata, start = uploadFile.xptr;
2371
+ if (start >= data.byteLength) {
2372
+ files.sendText(JSON.stringify({ action: 'uploaddone', reqid: uploadFile.xfilePtr }));
2373
+ } else {
2374
+ var end = uploadFile.xptr + 16384;
2375
+ if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
2376
+ var dataslice = new Uint8Array(data.slice(start, end))
2377
+ if ((dataslice[0] == 123) || (dataslice[0] == 0)) {
2378
+ var datapart = new Uint8Array(end - start + 1);
2379
+ datapart.set(dataslice, 1); // Add a zero char at the start of the send, this will indicate that it's not a JSON command.
2380
+ files.send(datapart);
2381
+ } else {
2382
+ files.send(dataslice); // The data does not start with 0 or 123 "{" so it can't be confused for JSON.
2383
+ }
2384
+ uploadFile.xptr = end;
2385
+ Q('d2progressBar').value = end;
2386
+ }
2387
+ }
2388
+
2389
+
2390
+
2391
+ //
2392
+ // POPUP DIALOG
2393
+ //
2394
+
2395
+ // null = Hidden, 1 = Generic Message
2396
+ var xxdialogMode;
2397
+ var xxdialogFunc;
2398
+ var xxdialogButtons;
2399
+ var xxdialogTag;
2400
+ var xxcurrentView = -1;
2401
+
2402
+ // Display a dialog box
2403
+ // Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
2404
+ function setDialogMode(x, y, b, f, c, tag) {
2405
+ xxdialogMode = x;
2406
+ xxdialogFunc = f;
2407
+ xxdialogButtons = b;
2408
+ xxdialogTag = tag;
2409
+ QE('idx_dlgOkButton', true);
2410
+ QV('idx_dlgOkButton', b & 1);
2411
+ QV('idx_dlgCancelButton', b & 2);
2412
+ QV('id_dialogclose', (b & 2) || (b & 8));
2413
+ QV('idx_dlgDeleteButton', b & 4);
2414
+ QV('idx_dlgButtonBar', b & 7);
2415
+ if (y) QH('id_dialogtitle', y);
2416
+ for (var i = 1; i < 8; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
2417
+ QV('dialog', x);
2418
+ if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
2419
+ }
2420
+
2421
+ function dialogclose(x) {
2422
+ var f = xxdialogFunc, b = xxdialogButtons, t = xxdialogTag;
2423
+ setDialogMode();
2424
+ if (((b & 8) || x) && f) f(x, t);
2425
+ }
2426
+
2427
+ function go(x) {
2428
+ if (xxdialogMode) return;
2429
+ QV('p11', x == 11);
2430
+ QV('p12', x == 12);
2431
+ QV('p13', x == 13);
2432
+ xxcurrentView = x;
2433
+ setupDeviceMenu();
2434
+ }
2435
+
2436
+ function setupDeviceMenu() {
2437
+ var menus = [];
2438
+ if (features & 2) { menus.push({ n: "Desktop", f: 'go(11)', s: (xxcurrentView == 11) }); }
2439
+ if (features & 1) { menus.push({ n: "Terminal", f: 'go(12)', s: (xxcurrentView == 12) }); }
2440
+ if (features & 4) { menus.push({ n: "Files", f: 'go(13)', s: (xxcurrentView == 13) }); }
2441
+ updateFooterMenu(menus);
2442
+ }
2443
+
2444
+ function updateFooterMenu(options) {
2445
+ while (options != null && options.length < 3) { options.push({ n: '' }); }
2446
+ var x = '', prev = '';
2447
+ if (options != null) { for (var i in options) { x += '<td style="cursor:pointer' + ((prev == '') ? '' : ';border-left:solid 1px white') + (options[i].s ? ';background-color:#487099' : '') + '" onclick="' + options[i].f + '">' + options[i].n; prev = options[i].n; } }
2448
+ QH('xfooterMenu', '<tr>' + x);
2449
+ }
2450
+
2451
+ function center() { if (xtermfit) xtermfit.fit(); QS('dialog').left = ((((getDocWidth() - 300) / 2)) + 'px'); deskAdjust(); }
2452
+ function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
2453
+ function messagebox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
2454
+ function statusbox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t); }
2455
+ function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
2456
+ function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }
2457
+ function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
2458
+ function setSessionActivity() { sessionActivity = Date.now(); /*QH('idleTimeoutNotify', '');*/ }
2459
+ function printDate(d) { return d.toLocaleDateString(urlargs.locale); }
2460
+ function printTime(d) { return d.toLocaleTimeString(urlargs.locale); }
2461
+ function printDateTime(d) { return d.toLocaleString(urlargs.locale); }
2462
+ function printFlexDateTime(d) { if (printDate(new Date()) == printDate(d)) { return format("Expires at {0}", printTime(d)); } else { return format("Expires {0}", printDateTime(d)); } }
2463
+ function getFileSizeStr(size) { if (typeof size != 'number') { size = 0; } if (size == 1) return "1 byte"; return format("{0} bytes", size); }
2464
+ function encodeURIComponentEx(txt) { return encodeURIComponent(txt).replace(/'/g, '%27'); };
2465
+ function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
2466
+ function focusTextBox(x) { setTimeout(function () { Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
2467
+ var isFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); } })();
2468
+
2469
+ // Webkit seems to have a problem with "download" tag causing "network error", but openning the download in a hidden frame fixes it.
2470
+ // So we do that for all browsers except FireFox
2471
+ function downloadFile(link, name, closeDialog) {
2472
+ var element = document.createElement('a');
2473
+ element.setAttribute('href', link);
2474
+ element.setAttribute('rel', 'noreferrer noopener');
2475
+ element.setAttribute('target', 'fileDownloadFrame');
2476
+ if (navigator.userAgent.indexOf('Firefox') >= 0) { element.setAttribute('download', decodeURIComponent(name ? name : '')); }
2477
+ document.body.appendChild(element);
2478
+ element.click();
2479
+ document.body.removeChild(element);
2480
+ if (closeDialog) { setDialogMode(0); }
2481
+ }
2482
+
2483
+ start();
2484
+ </script>
2485
+</body>
2486
+</html>
\ No newline at end of file
views/sharing-mobile.handlebars
+1730
-1577
@@ -1,4 +1,4 @@
1
-<!DOCTYPE html>
1
+<!DOCTYPE html>
2
<html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
3
<head>
4
<meta charset="utf-8">
@@ -7,31 +7,313 @@
7
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
8
<meta name="format-detection" content="telephone=no" />
9
<meta name="robots" content="noindex,nofollow">
10
- <link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS" />
11
- <link type="text/css" href="styles/style-sharing.css" media="screen" rel="stylesheet" title="CSS" />
12
- <link type="text/css" href="styles/xterm.css" media="screen" rel="stylesheet" title="CSS" />
10
+ <link rel="manifest" href="{{{domainurl}}}manifest.json">
11
+ <link rel="shortcut icon" href="{{{domainurl}}}favicon.ico" />
12
+ <link rel="icon" type="image/png" sizes="16x16" href="{{{domainurl}}}favicon-16x16.png">
13
+ <link rel="icon" type="image/png" sizes="32x32" href="{{{domainurl}}}favicon-32x32.png">
14
<link rel="apple-touch-icon" href="/favicon-303x303.png" />
15
+ <link type="text/css" href="styles/xterm.css" media="screen" rel="stylesheet" title="CSS" />
16
<meta name="apple-mobile-web-app-capable" content="yes">
17
<meta name="apple-mobile-web-app-status-bar-style" content="#ffffff">
18
<meta name="apple-mobile-web-app-title" content="{{{title}}}">
17
- <script type="text/javascript" src="scripts/common-0.0.1{{min}}.js"></script>
18
- <script type="text/javascript" src="scripts/amt-redir-ws-0.1.0{{{min}}}.js"></script>
19
- <script type="text/javascript" src="scripts/amt-wsman-ws-0.2.0{{{min}}}.js"></script>
19
+ <script type="text/javascript" src="scripts/common-0.0.1{{{min}}}.js"></script>
20
+ <script type="text/javascript" src="scripts/meshcentral{{{min}}}.js"></script>
21
<script type="text/javascript" src="scripts/agent-redir-ws-0.1.1{{{min}}}.js"></script>
21
- <script type="text/javascript" src="scripts/agent-redir-rtc-0.1.0{{{min}}}.js"></script>
22
- <script type="text/javascript" src="scripts/agent-desktop-0.0.2{{min}}.js"></script>
23
- <script type="text/javascript" src="scripts/amt-desktop-0.0.2{{min}}.js"></script>
24
- <script type="text/javascript" src="scripts/amt-terminal-0.0.2{{min}}.js"></script>
25
- <script type="text/javascript" src="scripts/zlib{{min}}.js"></script>
26
- <script type="text/javascript" src="scripts/zlib-inflate{{min}}.js"></script>
27
- <script type="text/javascript" src="scripts/zlib-adler32{{min}}.js"></script>
28
- <script type="text/javascript" src="scripts/zlib-crc32{{min}}.js"></script>
29
- <script type="text/javascript" src="scripts/amt-terminal-0.0.2{{min}}.js"></script>
22
+ <script type="text/javascript" src="scripts/agent-desktop-0.0.2{{{min}}}.js"></script>
23
+ <script type="text/javascript" src="scripts/amt-0.2.0{{{min}}}.js"></script>
24
+ <script type="text/javascript" src="scripts/amt-redir-ws-0.1.0{{{min}}}.js"></script>
25
+ <script type="text/javascript" src="scripts/amt-desktop-0.0.2{{{min}}}.js"></script>
26
<script type="text/javascript" src="scripts/xterm{{{min}}}.js"></script>
27
<script type="text/javascript" src="scripts/xterm-addon-fit{{{min}}}.js"></script>
28
+ <script type="text/javascript" src="scripts/zlib{{{min}}}.js"></script>
29
+ <script type="text/javascript" src="scripts/zlib-inflate{{{min}}}.js"></script>
30
+ <script type="text/javascript" src="scripts/zlib-adler32{{{min}}}.js"></script>
31
+ <script type="text/javascript" src="scripts/zlib-crc32{{{min}}}.js"></script>
32
<script keeplink=1 type="text/javascript" src="scripts/filesaver.min.js"></script>
33
+ <meta name="msapplication-TileColor" content="#00aba9">
34
+ <meta name="theme-color" content="#ffffff">
35
<title>{{{title}}}</title>
36
<style>
37
+ body {
38
+ background-color: white;
39
+ }
40
+
41
+ .night body {
42
+ background-color: black;
43
+ }
44
+
45
+ #MxMESH {
46
+ color: black;
47
+ }
48
+
49
+ .night #MxMESH {
50
+ color: lightgray;
51
+ }
52
+
53
+ .textOverGray { color: black; }
54
+
55
+ #dialog {
56
+ z-index:1000;
57
+ background-color:#EEE;
58
+ box-shadow:0px 0px 15px #666;
59
+ font-family:Arial,Helvetica,sans-serif;
60
+ border-radius:5px;
61
+ position:fixed;
62
+ top:90px;
63
+ width:300px;
64
+ }
65
+
66
+ .night #dialog {
67
+ color: black;
68
+ background-color:#AAA;
69
+ }
70
+
71
+ :focus {
72
+ outline: 0;
73
+ }
74
+
75
+ a {
76
+ color: #036;
77
+ text-decoration: underline;
78
+ }
79
+
80
+ .night a {
81
+ color: #99F;
82
+ }
83
+
84
+ #footer a {
85
+ color: #fff;
86
+ text-decoration: underline;
87
+ }
88
+
89
+ #footer a:hover {
90
+ text-decoration: none;
91
+ }
92
+
93
+ .night #footer {
94
+ color: gray;
95
+ }
96
+
97
+ .i1 {
98
+ background: url(../images/icons50.png) 0px 0px;
99
+ background-image: image-set(url(../images/icons50.png) 1x, url(../images/icons100.png) 2x);
100
+ height: 50px;
101
+ width: 50px;
102
+ border: none;
103
+ }
104
+
105
+ .i2 {
106
+ background: url(../images/icons50.png) -50px 0px;
107
+ background-image: image-set(url(../images/icons50.png) 1x, url(../images/icons100.png) 2x);
108
+ height: 50px;
109
+ width: 50px;
110
+ border: none;
111
+ }
112
+
113
+ .i3 {
114
+ background: url(../images/icons50.png) -100px 0px;
115
+ background-image: image-set(url(../images/icons50.png) 1x, url(../images/icons100.png) 2x);
116
+ height: 50px;
117
+ width: 50px;
118
+ border: none;
119
+ }
120
+
121
+ .i4 {
122
+ background: url(../images/icons50.png) -150px 0px;
123
+ background-image: image-set(url(../images/icons50.png) 1x, url(../images/icons100.png) 2x);
124
+ height: 50px;
125
+ width: 50px;
126
+ border: none;
127
+ }
128
+
129
+ .i5 {
130
+ background: url(../images/icons50.png) -200px 0px;
131
+ background-image: image-set(url(../images/icons50.png) 1x, url(../images/icons100.png) 2x);
132
+ height: 50px;
133
+ width: 50px;
134
+ border: none;
135
+ }
136
+
137
+ .i6 {
138
+ background: url(../images/icons50.png) -250px 0px;
139
+ background-image: image-set(url(../images/icons50.png) 1x, url(../images/icons100.png) 2x);
140
+ height: 50px;
141
+ width: 50px;
142
+ border: none;
143
+ }
144
+
145
+ .i7 {
146
+ background: url(../images/icons50.png) -300px 0px;
147
+ background-image: image-set(url(../images/icons50.png) 1x, url(../images/icons100.png) 2x);
148
+ height: 50px;
149
+ width: 50px;
150
+ border: none;
151
+ }
152
+
153
+ .i8 {
154
+ background: url(../images/icons50.png) -350px 0px;
155
+ background-image: image-set(url(../images/icons50.png) 1x, url(../images/icons100.png) 2x);
156
+ height: 50px;
157
+ width: 50px;
158
+ border: none;
159
+ }
160
+
161
+ .m0 {
162
+ background: url(../images/images16.png) -32px 0px;
163
+ height: 16px;
164
+ width: 16px;
165
+ border: none;
166
+ float: left;
167
+ }
168
+
169
+ .m1 {
170
+ background: url(../images/images16.png) -16px 0px;
171
+ height: 16px;
172
+ width: 16px;
173
+ border: none;
174
+ float: left;
175
+ }
176
+
177
+ .m2 {
178
+ background: url(../images/images16.png) -96px 0px;
179
+ height: 16px;
180
+ width: 16px;
181
+ border: none;
182
+ float: left;
183
+ }
184
+
185
+ .m3 {
186
+ background: url(../images/images16.png) -112px 0px;
187
+ height: 16px;
188
+ width: 16px;
189
+ border: none;
190
+ float: left;
191
+ }
192
+
193
+ .m4 {
194
+ background: url(../images/images16.png) -128px 0px;
195
+ height: 16px;
196
+ width: 16px;
197
+ border: none;
198
+ float: left;
199
+ }
200
+
201
+ .gray {
202
+ /*filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");*/ /* Firefox 10+, Firefox on Android */
203
+ filter: gray; /* IE6-9 */
204
+ -webkit-filter: grayscale(100%) opacity(60%); /* Chrome 19+, Safari 6+, Safari 6+ iOS */
205
+ }
206
+
207
+ .DevSt {
208
+ padding-left: 5px;
209
+ border-bottom-style: solid;
210
+ border-bottom-width: 1px;
211
+ border-bottom-color: #DDDDDD;
212
+ }
213
+
214
+ .noselect {
215
+ -webkit-touch-callout: none;
216
+ -webkit-user-select: none;
217
+ -khtml-user-select: none;
218
+ -moz-user-select: none;
219
+ -ms-user-select: none;
220
+ user-select: none;
221
+ }
222
+
223
+ .fileIcon1 {
224
+ background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb49Y2Sj9LT2f///yH5BAEAAAMALAAAAAAQABAAAAImnI+py+1vhJwyUYAzHTL4D3qdlJWaIFJqmKod607sDKIiDUP63hQAOw==);
225
+ height: 16px;
226
+ width: 16px;
227
+ cursor: pointer;
228
+ border: none;
229
+ float: left;
230
+ margin-top: 1px;
231
+ }
232
+
233
+ .fileIcon2 {
234
+ background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAM2xV/Xur+XPgP///yH5BAEAAAMALAAAAAAQABAAAAJD3ISZIGHWUGihznesYDYATFVM+D2hJ4lgN1olxALAtAlmPCJvuMmJd6PJckDYwicrHhTD5o7plJmg0Uc0asNMkphHAQA7);
235
+ height: 16px;
236
+ width: 16px;
237
+ cursor: pointer;
238
+ border: none;
239
+ float: left;
240
+ margin-top: 1px;
241
+ }
242
+
243
+ .fileIcon3 {
244
+ background: url(data:image/gif;base64,R0lGODlhEAAQAJEDAPb19IGBgbq6uv///yH5BAEAAAMALAAAAAAQABAAAAIy3ISpxgcPH2ouQgFEw1YmxnUXKEaaEZZnVWZk66JwzKpvuwZzwOgwb/C1gIOA8Yg8DgoAOw==);
245
+ height: 16px;
246
+ width: 16px;
247
+ cursor: pointer;
248
+ border: none;
249
+ float: left;
250
+ margin-top: 1px;
251
+ }
252
+
253
+ .fileIcon4 {
254
+ background: url(../images/meshicon16.png);
255
+ height: 16px;
256
+ width: 16px;
257
+ cursor: pointer;
258
+ border: none;
259
+ float: left;
260
+ margin-top: 1px;
261
+ }
262
+
263
+ .filelist {
264
+ -moz-user-select: none;
265
+ -khtml-user-select: none;
266
+ -webkit-user-select: none;
267
+ -o-user-select: none;
268
+ cursor: default;
269
+ -khtml-user-drag: element;
270
+ clear: both;
271
+ }
272
+
273
+ .style10 {
274
+ background-color: #C9C9C9;
275
+ color: #000;
276
+ }
277
+
278
+ .night .style10 {
279
+ background-color: #888;
280
+ }
281
+
282
+ .meshList {
283
+ width:auto;
284
+ height:40px;
285
+ background-color:lightgray;
286
+ margin-top:5px;
287
+ margin-bottom:5px;
288
+ margin-left:60px;
289
+ padding-top:5px;
290
+ padding-bottom:5px;
291
+ border-radius:8px 0px 0px 8px;
292
+ }
293
+
294
+ .night .meshList {
295
+ background-color: gray;
296
+ }
297
+
298
+ .night .devList3 {
299
+ background-color: gray;
300
+ }
301
+
302
+ .devList4 {
303
+ padding-left: 12px;
304
+ padding-top: 2px;
305
+ color: black;
306
+ }
307
+
308
+ .devList5 {
309
+ padding-left: 12px;
310
+ padding-top: 3px;
311
+ color: #444
312
+ }
313
+
314
+ .night .devList5 {
315
+ color: black;
316
+ }
317
318
.deskButton {
319
box-shadow: 0px 0px 10px #000;
@@ -57,220 +339,338 @@
339
z-index:1000;
340
}
341
60
- #dialog {
61
- z-index:1000;
62
- background-color:#EEE;
63
- box-shadow:0px 0px 15px #666;
64
- font-family:Arial,Helvetica,sans-serif;
65
- border-radius:5px;
66
- position:fixed;
67
- top:90px;
68
- width:300px;
342
+ #p15statetext {
343
+ padding: 4px;
344
+ height: 15px;
345
}
346
71
- .night #dialog {
347
+ #p15agentConsole {
348
+ background: black;
349
+ margin: 0;
350
+ padding: 0;
351
+ color: lightgray;
352
+ width: 100%;
353
+ position: relative;
354
+ }
355
+
356
+ #p15coreName {
357
+ padding: 4px;
358
+ display: inline-block;
359
+ }
360
+
361
+ #p15agentConsoleText {
362
+ position:absolute;
363
+ margin: 0;
364
+ padding: 0;
365
+ top: 0;
366
+ bottom: 0;
367
+ left:0;
368
+ right: 0;
369
+ overflow-y: scroll;
370
+ overflow-x: auto;
371
+ }
372
+
373
+ .areaHead {
374
+ padding-top: 2px;
375
+ padding-bottom: 2px;
376
+ background: #C0C0C0;
377
+ }
378
+
379
+ .night .areaHead {
380
+ color: #CCC;
381
+ background: #333;
382
+ }
383
+
384
+ .areaFoot {
385
+ padding-top: 2px;
386
+ padding-bottom: 2px;
387
+ background: #C0C0C0;
388
+ }
389
+
390
+ .night .areaFoot {
391
+ color: #CCC;
392
+ background: #333;
393
+ }
394
+
395
+ .toright2 {
396
+ float: right;
397
+ text-align: right;
398
+ }
399
+
400
+ #consoleTable {
401
+ width: 100%;
402
+ height: 100%;
403
+ padding: 0px;
404
+ margin-top: 0px;
405
+ }
406
+
407
+ .night #consoleTable {
408
color: black;
73
- background-color:#AAA;
409
}
410
411
+ #termTable {
412
+ width: 100%;
413
+ padding: 0px;
414
+ margin-top: 0px;
415
+ }
416
+
417
+ .fulldesk #termTable {
418
+ position: absolute;
419
+ top: 0;
420
+ bottom: 0;
421
+ left: 0;
422
+ right: 0;
423
+ }
424
+
425
+ #termarea3x {
426
+ background: black;
427
+ text-align: center;
428
+ height: 400px;
429
+ position: relative;
430
+ }
431
</style>
432
</head>
78
-<body style="overflow:hidden;background-color:black;margin:0;padding:0;border:0;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
79
- <div id=p11 class="noselect" style="overflow:hidden;position:absolute;left:0;top:0;right:0;bottom:32px;display:none">
80
- <div id=p10dialog style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:30px;width:300px;left:30px;display:none">
81
- <div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
82
- <div style=padding:5px>Keyboard Shortcuts Customization</div>
83
- <div style=width:100%;margin:6px></div>
84
- </div>
85
- <div style="margin-right:16px;margin-left:8px"><div id=p10dialog2 style="margin:auto;margin:3px"></div></div>
86
- <div style="padding:10px;margin-bottom:20px"><input type="button" value="OK" style="float:right;width:80px" onclick="deskCustomizeKeysEx()"></div>
87
- </div>
88
- <img id="deskkeybutton1" src="images/mobile-desk-exit.png" class="deskButton" style="top:10px;display:none" onclick="exitButton(event)" />
89
- <img id="deskkeybutton3a" src="images/mobile-desk-menu-open.png" class="deskButton" style="top:60px;display:none" onclick="toggleMenu(false)" />
90
- <img id="deskkeybutton3b" src="images/mobile-desk-menu-close.png" class="deskButton" style="top:60px;display:none" onclick="toggleMenu(true)" />
91
- <img id="deskkeybutton4a" src="images/mobile-desk-mouse-left.png" class="deskButton" style="top:110px;display:none" onclick="deskChangeMouseButton(0)" />
92
- <img id="deskkeybutton4b" src="images/mobile-desk-mouse-right.png" class="deskButton" style="top:110px;display:none" onclick="deskChangeMouseButton(1)" />
93
- <img id="deskkeybutton5a" src="images/mobile-desk-scale-out.png" class="deskButton" style="top:160px;display:none" onclick="deskChangeFullscreenZoom()" />
94
- <img id="deskkeybutton5b" src="images/mobile-desk-scale-in.png" class="deskButton" style="top:160px;display:none" onclick="deskChangeFullscreenZoom()" />
95
- <img id="deskkeybutton2a" src="images/mobile-desk-keyboard-open.png" class="deskButton" style="top:210px;display:none" onclick="toggleKeyboard()" />
96
- <img id="deskkeybutton2b" src="images/mobile-desk-keyboard-close.png" class="deskButton" style="top:210px;display:none" onclick="toggleKeyboard()" />
97
- <div style="position:absolute;top:0;left:0;z-index:200;opacity:0;width:1px;height:1px">
98
- <input id="softKeyboard" autocapitalize="off" autocomplete="off" type="text" spellcheck="false" style="z-index:200;opacity:0;width:1px;height:1px" onfocus="keyboardFocusChange()" onblur="keyboardFocusChange()" />
99
- </div>
100
- <div id="deskButtonMenu" style="display:none;position:absolute;top:10px;left:10px;right:55px;bottom:10px;z-index:1000"></div>
101
- <div id=deskarea0 style="position:absolute;top:0px;left:0px;right:0px;bottom:0px">
102
- <div id=deskarea1 class="areaHead" style="line-height:24px">
103
- <div class="toright2">
104
- <span id="p11power"></span>
105
- <input id="deskFullScreen" type="button" value="Full Screen" style="display:none" onkeypress="return false" onkeydown="return false" onclick="deskToggleFull(event)" class="mR" />
106
- <input id="deskActionsSettings" type="button" value="Settings..." onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" class="mR" />
107
- <div id="deskRecordIcon" class='deskareaicon' title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px"></div>
108
- </div>
109
- <div>
110
- <div id="idx_deskFullBtn2" onclick=deskToggleFull(event)> ✖</div>
111
- <span id=connectbutton1span><input type=button id=connectbutton1 cmenu="deskConnectButton" value="Connect" onclick=connectDesktop(event,3) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
112
- <span id=connectbutton1hspan> <input type=button id=connectbutton1h value="HW Connect" title="Connect using Intel AMT hardware KVM" onclick=connectDesktop(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
113
- <span id=disconnectbutton1span> <input type=button id=disconnectbutton1 value="Disconnect" onclick=connectDesktop(event,0) onkeypress="return false" onkeydown="return false" /></span>
114
- <span id="deskstatus">Disconnected</span><span id="deskmetadata"></span>
115
- </div>
116
- </div>
117
- <div id=deskarea3x style="max-height:calc(100vh - 60px);height:calc(100vh - 60px);">
118
- <div id=DeskParent>
119
- <canvas id=Desk width=640 height=480 oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event) onmousewheel=dmousewheel(event)></canvas>
433
+<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;margin:0;padding:0;border:0;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
434
+ <div id=container>
435
+ <div id="notifiyBox" class="notifiyBox" style="display:none"></div>
436
+ <div id=mastheadx></div>
437
+ <div id=masthead style="background:url(logo.png) 0px 0px;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
438
+ <div style="width:calc(100% - 50px);overflow:hidden">
439
+ <div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:6px">
440
+ <strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title1}}}</font></strong>
441
</div>
121
- <div id=p11DeskConsoleMsg style="display:none;text-align:left;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=clearConsoleMsg()></div>
122
- </div>
123
- <div id=deskarea4 class="areaFoot" style="min-height:24px">
124
- <div class="toright2">
125
- <span id="DeskLatency" title="Desktop Session Latency"></span>
126
- <span id="DeskTimer" style="display:none" title="Session time"></span>
127
- <select id=termdisplays style="display:none" onchange=deskSetDisplay(event) onkeypress="return false" onkeydown="return false"></select>
128
- <span id=DeskSaveImageButton title="Save a screenshot of the remote desktop"><img src='images/icon-camera.png' onclick=deskSaveImage() height=16 width=16 style=padding-top:2px /></span>
129
- </div>
130
- <div style="height:22px">
131
- <select id="deskkeys">
132
- <option value=10>Ctrl+Alt+Del</option>
133
- <option value=5>Win</option>
134
- <option value=0>Win+Down</option>
135
- <option value=1>Win+Up</option>
136
- <option value=2>Win+L</option>
137
- <option value=3>Win+M</option>
138
- <option value=4>Shift+Win+M</option>
139
- <option value=6>Win+R</option>
140
- <option value=7>Alt-F4</option>
141
- <option value=8>Ctrl-W</option>
142
- <option value=9>Alt-Tab</option>
143
- <option value=11>Win+Left</option>
144
- <option value=12>Win+Right</option>
145
- </select>
146
- <input id="DeskWD" type=button value="Send" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()" />
147
- <input id="DeskClip" style="" type="button" value="Clipboard" onkeypress="return false" onkeydown="return false" onclick="showDeskClip()" />
148
- <input id="DeskType" style="" type="button" value="Type" onkeypress="return false" onkeydown="return false" onclick="showDeskType()" />
149
- <label><span id="DeskControlSpan" title="Toggle mouse and keyboard input"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false" onclick="toggleKvmControl()" />Input</span></label>
442
+ <div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:10px">
443
+ <strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
444
</div>
445
</div>
446
</div>
153
- </div>
154
- <div id=p12 class="noselect" style="overflow:hidden;position:absolute;left:0;top:0;right:0;bottom:32px;display:none;background-color:black">
155
- <div id="p12warning" onclick=showFeaturesDlg()>
156
- <div class="icon2"></div>
157
- <div class="warningbox">Intel® AMT Redirection port or KVM feature is disabled<span id="p12warninga">, click here to enable it.</span></div>
158
- </div>
159
- <div id="p12warning2" onclick=showPowerActionDlg()>
160
- <div class="icon2"></div>
161
- <div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
162
- </div>
163
- <div class="areaHead" style="position:absolute;top:0;left:0;right:0;height:24px">
164
- <div class="toright2">
165
- <div id="termRecordIcon" class='deskareaicon' title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
166
- <div id="p12power" style="margin-top:3px;margin-right:4px;float:right"></div>
167
- </div>
168
- <div>
169
- <span id="connectbutton2span"><input type="button" id="connectbutton2" cmenu="termConnectButton" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
170
- <span id="disconnectbutton2span"> <input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false" /></span>
171
- <span id="termstatus">Disconnected</span><span id="termtitle"></span>
172
- </div>
173
- </div>
174
- <div id="termarea3xdiv" style="position:absolute;top:28px;bottom:28px;left:0;right:0"></div>
175
- <div class="areaFoot" style="position:absolute;bottom:0;left:0;right:0;height:24px">
176
- <div class="toright2">
177
- <span id="TermLatency" title="Terminal Session Latency"></span>
178
- <span id="TermTimer" title="Session time"></span>
179
- <span id="terminalSettingsButtons" style="display:none">
180
- <input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="CR+LF" title="Toggle what the return key will send" onclick="termToggleCr()" />
181
- <input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()" />
182
- <input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()" />
183
- </span>
184
- <span id="terminalSizeDropDown" style="display:none">
185
- <select id="termSizeList" onkeypress="return false"><option value="1">80x25</option><option value="2">100x30</option></select>
186
- </span>
187
- <span id="specialKeyDropDown">
188
- <select id="specialkeylist" onkeypress="return false"></select>
189
- <input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />
190
- </span>
191
- </div>
192
- <div>
193
-
194
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')" />
195
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')" />
196
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')" />
197
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')" style="display:none" />
198
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="pastebutton" value="Paste" title="Paste text into the terminal" onclick="showTermPasteDialog()" style="display:none" />
199
- </div>
200
- </div>
201
- <div id=p12TermConsoleMsg style="display:none;text-align:left;cursor:pointer;position:absolute;left:30px;top:45px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p12clearConsoleMsg()></div>
202
- </div>
203
- <div id=p13 class="noselect" style="overflow:hidden;position:absolute;left:0;top:0;right:0;bottom:32px;display:none;background-color:white">
204
- <div id="p13toolbar" style="position:absolute;left:0;top:0;right:0;bottom:28px">
205
- <div class="areaHead">
206
- <div class="toright2">
207
- <div id="filesRecordIcon" class='deskareaicon' title="Server is recording this session" style="display:none;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-left:5px"></div>
208
- <div id="p13power" style="margin-top:3px;margin-right:4px;float:right"></div>
447
+ <div id=page_content style="position:absolute;bottom:32px;top:50px;width:100%">
448
+ <div id=column_l style="width:100%;padding:0;position:absolute;bottom:0px;top:0px">
449
+ <div id=p0 style=display:none;width:100%;height:100%>
450
+ <div style="display:flex;align-items:center;width:100%;height:100%">
451
+ <div id=p0message style=text-align:center;width:100%><span id="p0span">Server disconnected</span>, <href onclick=reload() style=cursor:pointer><u>click to reconnect</u></href>.</div>
452
+ </div>
453
</div>
210
- <div>
211
- <input id=p13Connect value="Connect" onclick=connectFiles(event) type="button" />
212
- <span id=p13Status>Disconnected</span>
213
- </div>
214
- </div>
215
- <div id="fileArea2" class="areaHead2" valign=bottom>
216
- <div id="p13rightOfButtons" class="toright2"></div>
217
- <div>
218
- <input type=button id=p13FolderUp disabled="disabled" onclick="p13folderup()" value="Up" />
219
- <input type=button id=p13SelectAllButton disabled="disabled" onclick="p13selectallfile()" value="Select All" />
220
- <input type=button id=p13RenameFileButton disabled="disabled" value="Rename" onclick="p13renamefile()" />
221
- <input type=button id=p13DeleteFileButton disabled="disabled" value="Delete" onclick="p13deletefile()" />
222
- <input type=button id=p13ViewFileButton disabled="disabled" value="Edit" onclick="p13viewfile()" />
223
- <input type=button id=p13NewFolderButton disabled="disabled" value="New Folder" onclick="p13createfolder()" />
224
- <input type=button id=p13UploadButton disabled="disabled" value="Upload" onclick="p13uploadFile()" />
225
- <input type=button id=p13CutButton disabled="disabled" value="Cut" onclick="p13copyFile(1)" />
226
- <input type=button id=p13CopyButton disabled="disabled" value="Copy" onclick="p13copyFile(0)" />
227
- <input type=button id=p13PasteButton disabled="disabled" value="Paste" onclick="p13pasteFile()" />
228
- <input type=button id=p13ZipButton disabled="disabled" value="Zip" onclick="p13zipFiles()" />
229
- <input type=button id=p13RefreshButton disabled="disabled" value="Refresh" onclick="p13folderup(9999)" />
230
- <input type=button id=p13FindButton disabled="disabled" value="Find" onclick="p13findfile()" />
231
- </div>
232
- </div>
233
- <div class="areaHead3" style="line-height:28px">
234
- <div class="toright2">
235
- <select id=p13sortdropdown onchange=p13updateFiles()>
236
- <option value=1 selected="selected">Sort by name</option>
237
- <option value=2>Sort by size</option>
238
- <option value=3>Sort by date</option>
239
- <option value=4>Descend by name</option>
240
- <option value=5>Descend by size</option>
241
- <option value=6>Descend by date</option>
242
- </select>
454
+ <div id=p1 style=display:none;width:100%;height:100%>
455
+ <div style="display:flex;align-items:center;width:100%;height:100%">
456
+ <div id=p1message style=text-align:center;width:100%></div>
457
+ </div>
458
</div>
244
- <div> <span id="p13currentpath"></span></div>
245
- </div>
246
- <div id="fileArea4" style="height:calc(100vh - 146px)">
247
- <div id=p13FilesConsoleMsg style="display:none;text-align:left;cursor:pointer;position:absolute;left:30px;top:165px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p13clearConsoleMsg()></div>
248
- <div id="p13filetable" style="width:100%;height:100%">
249
- <div id="p13bigok" style="display:none"><b>✓</b></div>
250
- <div id="p13bigfail" style="display:none"><b>✗</b></div>
251
- <span id="p13files"></span>
459
+ <div id=p10 style=display:none;position:absolute;bottom:0;top:0;width:100%;overflow:hidden>
460
+ <table id=p10deskTopTable cellspacing=0 style="margin:0;padding:0;border-spacing:0;border:0;position:absolute;top:0">
461
+ <tr style=padding:0>
462
+ <td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width=60px valign=top onclick=goBack()>
463
+ <div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
464
+ <div class="menucurve"></div>
465
+ </div>
466
+ <div style="padding:0;font-size:25px;background-color:#036;width:50px;border-radius:0 0 10px 0;height:36px">◀</div>
467
+ </td>
468
+ <td>
469
+ <a id=MainComputerImage style=cursor:pointer onclick=p10showiconselector()></a>
470
+ </td>
471
+ <td>
472
+ <div style=margin-left:5px>
473
+ <strong><span id=p10deviceName></span></strong><br />
474
+ <span id=MainComputerState></span>
475
+ </div>
476
+ </td>
477
+ </tr>
478
+ </table>
479
+ <div id=p10dialog style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:30px;width:300px;left:30px;display:none">
480
+ <div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
481
+ <div style=padding:5px>Keyboard Shortcuts Customization</div>
482
+ <div style=width:100%;margin:6px></div>
483
+ </div>
484
+ <div style="margin-right:16px;margin-left:8px"><div id=p10dialog2 style="margin:auto;margin:3px"></div></div>
485
+ <div style="padding:10px;margin-bottom:20px"><input type="button" value="OK" style="float:right;width:80px" onclick="deskCustomizeKeysEx()"></div>
486
+ </div>
487
+ <img id="deskkeybutton1" src="images/mobile-desk-exit.png" class="deskButton" style="top:10px;display:none" onclick="exitButton()" />
488
+ <img id="deskkeybutton3a" src="images/mobile-desk-menu-open.png" class="deskButton" style="top:60px;display:none" onclick="toggleMenu(false)" />
489
+ <img id="deskkeybutton3b" src="images/mobile-desk-menu-close.png" class="deskButton" style="top:60px;display:none" onclick="toggleMenu(true)" />
490
+ <img id="deskkeybutton4a" src="images/mobile-desk-mouse-left.png" class="deskButton" style="top:110px;display:none" onclick="deskChangeMouseButton(0)" />
491
+ <img id="deskkeybutton4b" src="images/mobile-desk-mouse-right.png" class="deskButton" style="top:110px;display:none" onclick="deskChangeMouseButton(1)" />
492
+ <img id="deskkeybutton5a" src="images/mobile-desk-scale-out.png" class="deskButton" style="top:160px;display:none" onclick="deskChangeFullscreenZoom()" />
493
+ <img id="deskkeybutton5b" src="images/mobile-desk-scale-in.png" class="deskButton" style="top:160px;display:none" onclick="deskChangeFullscreenZoom()" />
494
+ <img id="deskkeybutton2a" src="images/mobile-desk-keyboard-open.png" class="deskButton" style="top:210px;display:none" onclick="toggleKeyboard()" />
495
+ <img id="deskkeybutton2b" src="images/mobile-desk-keyboard-close.png" class="deskButton" style="top:210px;display:none" onclick="toggleKeyboard()" />
496
+ <div style="position:absolute;top:0;left:0;z-index:200;opacity:0;width:1px;height:1px">
497
+ <input id="softKeyboard" autocapitalize="off" autocomplete="off" type="text" spellcheck="false" style="z-index:200;opacity:0;width:1px;height:1px" onfocus="keyboardFocusChange()" onblur="keyboardFocusChange()" />
498
+ </div>
499
+ <div id="deskButtonMenu" style="display:none;position:absolute;top:10px;left:10px;right:55px;bottom:10px;z-index:1000"></div>
500
+ <div id=p10desktop style="overflow:hidden;position:absolute;top:55px;bottom:0px;width:100%;display:none">
501
+ <div id=deskarea1 style="position:absolute;top:0px;width:100%;height:32px">
502
+ <div style="padding-top:2px;padding-bottom:2px;background:#C0C0C0;height:32px">
503
+ <div style="float:right;text-align:right">
504
+ <span id="p14power"></span>
505
+ <input type=button id=deskFullScreen value="Full Screen" onclick=deskToggleFull(event) onkeypress="return false" onkeydown="return false" disabled="disabled" style="height:28px;margin-right:3px;">
506
+ </div>
507
+ <div style="margin-left:3px">
508
+ <input type=button id=connectbutton1 value="Connect" onclick=connectDesktop(event,3) onkeypress="return false" onkeydown="return false" disabled="disabled" style="height:28px">
509
+ <input type=button id=connectbutton1h value="HW Connect" onclick=connectDesktop(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled" style="height:28px">
510
+ <input type=button id=disconnectbutton1 value="Disconnect" onclick=connectDesktop(event,0) onkeypress="return false" onkeydown="return false" style="height:28px">
511
+ <span id="deskstatus" style="color:black">Disconnected</span>
512
+ </div>
513
+ </div>
514
+ </div>
515
+ <div id=deskarea3 style="position:absolute;top:32px;width:100%;height:calc(100% - 64px);background-color:#000;text-align:center">
516
+ <div id=DeskParent style="height:100%">
517
+ <canvas id=Desk width=640 height=200 style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event) onmousewheel=dmousewheel(event)></canvas>
518
+ </div>
519
+ <div id=p11DeskConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px;text-align:left" onclick=p11clearConsoleMsg()></div>
520
+ <div id=p11DeskSessionSelector style="display:none;position:absolute;left:30px;top:17px;right:30px;bottom:17px;overflow-y:auto"></div>
521
+ </div>
522
+ <div id=deskarea4 style="position:absolute;bottom:0px;width:100%;height:32px">
523
+ <div style=padding-top:2px;padding-bottom:2px;background:#C0C0C0>
524
+ <div style=float:right;text-align:right>
525
+ <span id=DeskChatButton><img src='images/icon-chat.png' onclick=deviceChat(event) height=16 width=16 style=padding-top:5px;cursor:pointer /></span>
526
+ <span id=DeskToastButton><img src='images/icon-notify.png' onclick=deviceToastFunction() height=16 width=16 style=padding-top:5px;cursor:pointer /></span>
527
+ <!--<input id=DeskToolsButton type=button value=Tools onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()"> -->
528
+ </div>
529
+ <div>
530
+ <input id="deskActionsBtn" type=button style="margin-left:3px;height:28px" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() />
531
+ <input type="button" value="Settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" style="height:28px">
532
+ <input type="button" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="display:none;height:28px">
533
+ <!--<input type="button" id="DeskSpecialKeys" value="Keys" onkeypress="return false" onkeydown="return false" onclick="sendSpecialKeys()" style="height:28px">-->
534
+ <input type="button" id="DeskScreens" value="Screens" onkeypress="return false" onkeydown="return false" onclick="deskSelectScreens()" style="display:none;height:28px">
535
+ <label><span id="DeskControlSpan" style="display:none"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false">Input</span></label>
536
+ </div>
537
+ </div>
538
+ </div>
539
+ </div>
540
+ <div id="termButtonMenu" style="display:none;position:absolute;top:10px;left:10px;right:55px;bottom:10px;z-index:1000"></div>
541
+ <div id=p10terminal style="overflow:hidden;position:absolute;top:55px;bottom:0px;width:100%;display:none;background-color:#333">
542
+ <div id=termTable style="position:absolute;top:0;bottom:0;left:0;right:0">
543
+ <div id="termarea1">
544
+ <div class="areaHead" style="line-height:24px">
545
+ <div class="toright2">
546
+ <input type=button id=termFullScreen value="Full Screen" onclick=deskToggleFull(event) onkeypress="return false" onkeydown="return false" disabled="disabled" style="height:28px;margin-right:3px;">
547
+ <div id="terminalCustomUpperRight" style="float:left;margin-right:6px"></div>
548
+ </div>
549
+ <div>
550
+ <span id="connectbutton2span" style="margin-left:3px"><input type="button" id="connectbutton2" cmenu="termConnectButton" value="Connect" style="height:28px" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
551
+ <span id="disconnectbutton2span" style="margin-left:3px"><input type="button" id="disconnectbutton2" value="Disconnect" style="height:28px" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false" /></span>
552
+ <span id="termstatus" style="line-height:22px">Disconnected</span><span id="termtitle"></span>
553
+ </div>
554
+ </div>
555
+ </div>
556
+ <div id="termarea3" style="width:100%;height: calc(100% - 60px);" cellpadding=0 cellspacing=0>
557
+ <div id="termarea3x" style="width:100%;height:100%">
558
+ <div style="width:100%;height:100%" id="termarea3xdiv"></div>
559
+ </div>
560
+ </div>
561
+ <div id="termarea4" style="position:relative;height:32px;">
562
+ <div class="areaFoot">
563
+ <div class="toright2"></div>
564
+ <div style="height:28px">
565
+ <input id="termActionsBtn" style="margin-left:3px;height:28px" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() />
566
+ </div>
567
+ </div>
568
+ </div>
569
+ <div id=p12TermConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:45px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p12clearConsoleMsg()></div>
570
+ </div>
571
+ </div>
572
+ <div id=p10files style="position:absolute;top:55px;bottom:0px;width:100%;display:none">
573
+ <table id="p13toolbar" style="width:100%;height:111px" cellpadding="0" cellspacing="0">
574
+ <tr>
575
+ <td style="background-color:#C0C0C0;border-bottom:2px solid black;padding:2px;line-height:24px">
576
+ <div style="float:right;text-align:right">
577
+ <input id="filesActionsBtn" type=button onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() style=margin-right:2px />
578
+ <div id="filesCustomUpperRight" style="float:left;margin-right:6px"></div>
579
+ </div>
580
+ <div style="margin-left:2px">
581
+ <input id=p13AutoConnect value="AutoConnect" onclick=autoConnectFiles(event) onkeypress="return false" onkeydown="return false" type="button" style="display:none">
582
+ <input id=p13Connect value="Connect" onclick=connectFiles(event) onkeypress="return false" onkeydown="return false" type="button">
583
+ <span class=textOverGray id=p13Status>Disconnected</span>
584
+ </div>
585
+ </td>
586
+ </tr>
587
+ <tr>
588
+ <td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign=bottom>
589
+ <div style="width:100%;text-align:center">
590
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13FolderUp disabled="disabled" onclick="p13folderup()" value="Up" />
591
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13SelectAllButton disabled="disabled" onclick="p13selectallfile()" value="SelectAll" onkeypress="return false" onkeydown="return false" />
592
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13RenameFileButton disabled="disabled" value="Rename" onclick="p13renamefile()" onkeypress="return false" onkeydown="return false" />
593
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13DeleteFileButton disabled="disabled" value="Delete" onclick="p13deletefile()" onkeypress="return false" onkeydown="return false" />
594
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13NewFolderButton disabled="disabled" value="Folder" onclick="p13createfolder()" onkeypress="return false" onkeydown="return false" />
595
+ </div>
596
+ <div style="width:100%;text-align:center">
597
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13UploadButton disabled="disabled" value="Upload" onclick="p13uploadFile()" onkeypress="return false" onkeydown="return false" />
598
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13CutButton disabled="disabled" value="Cut" onclick="p13copyFile(1)" onkeypress="return false" onkeydown="return false" />
599
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13CopyButton disabled="disabled" value="Copy" onclick="p13copyFile(0)" onkeypress="return false" onkeydown="return false" />
600
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13PasteButton disabled="disabled" value="Paste" onclick="p13pasteFile()" onkeypress="return false" onkeydown="return false" />
601
+ <input type=button style="width:calc(100%/5 - 5px)" id=p13RefreshButton disabled="disabled" value="Refresh" onclick="p13folderup(9999)" onkeypress="return false" onkeydown="return false" />
602
+ </div>
603
+ </td>
604
+ </tr>
605
+ <tr>
606
+ <td style="background-color:#E4E9E7;height:28px">
607
+ <table style="width:100%">
608
+ <tr>
609
+ <td id=p13currentpath style="overflow:hidden;padding-left:4px;padding-top:2px;color:black"></td>
610
+ <td style="text-align:right;padding-right:4px">
611
+ <select id=p13sortdropdown onchange=p13updateFiles()>
612
+ <option value=1 selected="selected">Sort by name</option>
613
+ <option value=2>Sort by size</option>
614
+ <option value=3>Sort by date</option>
615
+ <option value=4>Descend by name</option>
616
+ <option value=5>Descend by size</option>
617
+ <option value=6>Descend by date</option>
618
+ </select>
619
+ </td>
620
+ </tr>
621
+ </table>
622
+ </td>
623
+ </tr>
624
+ </table>
625
+ <div id=p13FilesConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:165px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=p13clearConsoleMsg()></div>
626
+ <div id="p13filetable" style="width:100%;height:calc(100% - 133px);overflow:auto;-webkit-user-select:none">
627
+ <!--
628
+ <div id="p13bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✓</b></div>
629
+ <div id="p13bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✗</b></div>
630
+ -->
631
+ <span id="p13files"></span>
632
+ </div>
633
+ <table id="p13toolbarBottom" style="width:100%;height:22px;position:absolute;bottom:0px" cellpadding=0 cellspacing=0>
634
+ <tr><td style="text-align:left;padding:3px;text-align:center;background-color:#D3D9D6;color:black"> <span id="p13bottomstatus"></span></td></tr>
635
+ </table>
636
+ </div>
637
</div>
638
</div>
639
</div>
255
- <div class="areaFoot" style="position:absolute;left:0;right:0;bottom:0;height:28px">
256
- <span id="p13bottomstatus"></span>
640
+ <div id=footer style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px">
641
+ <table id=footerMenu cellpadding=0 cellspacing=0 style="height:32px;width:100%;color:white;cursor:pointer;table-layout:fixed"></table>
642
</div>
643
</div>
259
- <div id=xfooter style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px;margin:0;padding:0">
260
- <table id=xfooterMenu cellpadding=0 cellspacing=0 style="height:32px;width:100%;color:white;cursor:pointer;table-layout:fixed"></table>
261
- </div>
262
- <div id=dialog class="noselect" style="display:none">
263
- <div id=dialogHeader>
264
- <div tabindex=0 id=id_dialogclose onclick=setDialogMode() onkeypress="if (event.key == 'Enter') setDialogMode()">✖</div>
265
- <div id=id_dialogtitle></div>
644
+ <div id=dialog style="display:none">
645
+ <div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
646
+ <div id=id_dialogclose style=float:right;padding:5px;cursor:pointer onclick=setDialogMode()><b>X</b></div>
647
+ <div id=id_dialogtitle style=padding:5px></div>
648
+ <div style=width:100%;margin:6px></div>
649
</div>
267
- <div id=dialogBody>
268
- <div id=dialog1>
269
- <div id=id_dialogMessage style=""></div>
650
+ <div style="margin-right:16px;margin-left:8px">
651
+ <div id=dialog1 style="margin:auto;text-align:center;margin:3px">
652
+ <div id=id_dialogMessage style="padding:10px"></div>
653
</div>
271
- <div id=dialog2 style="">
654
+ <div id=dialog2 style="margin:auto;margin:3px">
655
<div id=id_dialogOptions></div>
656
</div>
657
+ <div id=dialog3 style="margin:auto;margin:3px">
658
+ <select id="deskkeys" style="width:100%">
659
+ <option value=10>Ctrl+Alt+Del</option>
660
+ <option value=11>Tab</option>
661
+ <option value=5>Win</option>
662
+ <option value=0>Win+Down</option>
663
+ <option value=1>Win+Up</option>
664
+ <option value=2>Win+L</option>
665
+ <option value=3>Win+M</option>
666
+ <option value=4>Shift+Win+M</option>
667
+ <option value=6>Win+R</option>
668
+ <option value=7>Alt-F4</option>
669
+ <option value=8>Ctrl-W</option>
670
+ <option value=9>Alt-Tab</option>
671
+ <option value=12>Shift-F10</option>
672
+ </select>
673
+ </div>
674
<div id=dialog7 style="margin:auto;margin:3px">
675
<div id="d7meshkvm">
676
<h4 style="width:100%;border-bottom:1px solid gray">Agent Remote Desktop</h4>
@@ -339,198 +739,346 @@
739
</div>
740
</div>
741
</div>
342
- <div id="idx_dlgButtonBar">
343
- <input id="idx_dlgCancelButton" type="button" value="Cancel" style="" onclick="dialogclose(0)">
344
- <input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
345
- <div><input id="idx_dlgDeleteButton" type="button" value="Delete" style="display:none" onclick="dialogclose(2)"></div>
742
+ <div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:20px">
743
+ <input id="idx_dlgCancelButton" type="button" value="Cancel" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
744
+ <input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">
745
+ <div><input id="idx_dlgDeleteButton" type="button" value="Delete" style="display:none" onclick="dialogclose(2)" /></div>
746
</div>
747
</div>
748
+ <div id=topMenu style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:0px 0px 5px 5px;position:fixed;top:50px;right:5px;width:170px;display:none">
749
+ <div style="padding:12px;border-top:1px solid gray;color:black;cursor:pointer" onclick=topMenu(2)>My Files</div>
750
+ <div style="padding:12px;border-top:1px solid gray;color:black;cursor:pointer" onclick=topMenu(1)>My Account</div>
751
+ <div id="logoutMenuOption"><a href=/logout><div style="padding:12px;border-top:1px solid gray;color:black;cursor:pointer">Logout</div></a></div>
752
+ </div>
753
+ <audio id="chimes"><source src="sounds/chimes.mp3" type="audio/mp3" /></audio>
754
+ <iframe name="fileUploadFrame" style=display:none></iframe>
755
<script>
349
- var sessionActivity = null;
350
- var desktop = null;
351
- var agentPresent = true;
352
- var intelAmtPresent = false;
353
- var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 100, localkeymap: false };
354
- var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
756
+ 'use strict';
757
+ var args = parseUriArgs();
758
+ var sessionTime = parseInt('{{{sessiontime}}}');
759
+ var sessionRefreshTimer = null;
760
var domain = '{{{domain}}}';
761
var domainUrl = '{{{domainurl}}}';
762
var authCookie = '{{{authCookie}}}';
763
+ var authRelayCookie = '{{{authRelayCookie}}}';
764
var viewOnly = parseInt('{{{viewOnly}}}');
359
- var urlargs = parseUriArgs();
360
- var debugmode = urlargs.debug;
765
+ var authCookieRenewTimer = null;
766
+ var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
767
+ var debugmode = false;
768
var attemptWebRTC = false;
362
- var updateSessionTimer = null;
363
- var deskKeyboardShortcuts = [];
769
var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel® AMT Connected"];
365
- var nodeName = decodeURIComponent('{{{nodeName}}}');
366
- var webPageFullScreen = false;
367
- var expire = '{{{expire}}}';
368
- if (expire != '') {
369
- QH('p11power', printFlexDateTime(new Date(parseInt(expire))));
370
- QH('p12power', printFlexDateTime(new Date(parseInt(expire))));
371
- QH('p13power', printFlexDateTime(new Date(parseInt(expire))));
372
- }
373
- var features = parseInt('{{{features}}}');
374
- var features2 = parseInt('{{{features2}}}');
375
-
376
- // Load desktop settings
377
- var t = null;
378
- try { t = localStorage.getItem('desktopsettings'); } catch (ex) { }
379
- if (t != null) { try { desktopsettings = JSON.parse(t); } catch (ex) { } }
380
- if (((features2 & 1) == 0) && (desktopsettings.quality > 60)) { desktopsettings.quality = 60; }
381
-
382
- // Terminal
383
- var terminal = null;
770
+ var files;
771
+ var terminal;
772
+ var sessionActivity = Date.now();
773
+ var deskPinchZoom;
774
+ var deskKeyboardShortcuts = [];
775
var xterm = null;
776
var xtermfit = null;
777
var xtermResizeTimer = null;
778
+ var features = parseInt('{{{features}}}');
779
+ var features2 = parseInt('{{{features2}}}');
780
388
- // Files
389
- var files = null
390
-
391
- // Console messages timers
781
+ // Console Message Display Timers
782
var p11DeskConsoleMsgTimer = null;
783
var p12TermConsoleMsgTimer = null;
784
var p13FilesConsoleMsgTimer = null;
785
396
- function start() {
786
+ // Check if WebP is supported
787
+ var webpSupport = false;
788
+ check_webp_feature('lossy', function (f, x) { webpSupport = x; });
789
+
790
+ function startup() {
791
+ if ((features & 32) == 0) {
792
+ // Guard against other site's top frames (web bugs).
793
+ var loc = null;
794
+ try { loc = top.location.toString().toLowerCase(); } catch (e) { }
795
+ if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
796
+ }
797
+ if (!args.locale) { var x = getstore('loctag', 0); if ((x != null) && (x != '*')) { args.locale = x; } }
798
+
799
window.onresize = center;
800
center();
801
+ go(10);
802
+
803
+ // Document keys
804
document.onkeypress = ondeskkeypress;
805
document.onkeydown = ondeskkeydown;
806
document.onkeyup = ondeskkeyup;
402
- //document.onkeypress = ondockeypress;
403
- //document.onkeydown = ondockeydown;
404
- //document.onkeyup = ondockeyup;
405
- setupDesktop();
406
- setupTerminal();
407
- setupFiles();
408
-
409
- // Set the document title
410
- if (nodeName.length > 0) { document.title += ' - ' + nodeName; }
411
-
412
- // View only mode
413
- if (viewOnly == 1) {
414
- QV('deskkeys', false);
415
- QV('DeskWD', false);
416
- QV('DeskClip', false);
417
- QV('DeskType', false);
418
- QV('DeskControlSpan', false);
419
- }
807
+ document.onclick = function (e) { if ((xxdialogMode == 999) && (e.target.id != 'topMenuIcon')) { QV('topMenu', false); xxdialogMode = 0; } }
808
421
- // Setup upload drag & drop
422
- Q('p13filetable').addEventListener('drop', p13fileDragDrop, false);
423
- Q('p13filetable').addEventListener('dragover', p13fileDragOver, false);
424
- Q('p13filetable').addEventListener('dragleave', p13fileDragLeave, false);
425
-
426
- // Setup feature visibility
427
- QV('LeftMenuDesktop', features & 2);
428
- QV('LeftMenuTerminal', features & 1);
429
- QV('LeftMenuFiles', features & 4);
430
- if (features & 2) { go(11); } // Goto desktop
431
- else if (features & 1) { go(12); } // Goto terminal
432
- else if (features & 4) { go(13); } // Goto files
433
- deskAdjust();
809
+ // Load desktop settings
810
+ var t = localStorage.getItem('desktopsettings');
811
+ if (t != null) { desktopsettings = JSON.parse(t); }
812
+ applyDesktopSettings();
813
+
814
+ attemptWebRTC = false; // For now, default WebRTC off unless we set it in the URL.
815
+ if (args.webrtc != null) { attemptWebRTC = (args.webrtc == 1); }
816
817
// Set the user's desktop shortcut keys
818
deskKeyboardShortcuts = [];
437
- var deskKeyboardShortcutsStr = '0x0A002E,0x100000,0x100028,0x100026,0x10004C,0x10004D,0x11004D,0x100052,0x020073,0x080057,0x020009,0x100025,0x100027'.split(',');
819
+ var deskKeyboardShortcutsStr = getstore('deskKeyShortcuts', '0x0A002E,0x100000,0x100028,0x100026,0x10004C,0x10004D,0x11004D,0x100052,0x020073,0x080057,0x020009,0x100025,0x100027').split(',');
820
for (var i in deskKeyboardShortcutsStr) { deskKeyboardShortcuts.push(parseInt(deskKeyboardShortcutsStr[i])); }
821
updateDeskShortcutKeys();
440
- //updateTermShortcutKeys();
822
+ updateTermShortcutKeys();
823
+
824
+ if (features & 2) { currentDevicePanel = 1; } // Goto desktop
825
+ else if (features & 1) { currentDevicePanel = 5; } // Goto terminal
826
+ else if (features & 4) { currentDevicePanel = 2; } // Goto files
827
+ setupDeviceMenu(currentDevicePanel);
828
}
829
830
+ function setSessionActivity() { sessionActivity = Date.now(); }
831
+ function checkIdleSessionTimeout() { var delta = (Date.now() - sessionActivity); if (delta > serverinfo.timeout) { window.location.href = 'logout'; } }
832
+
833
//
444
- // Desktop
834
+ // Menu System
835
//
836
447
- function isInputAllowed() { return (viewOnly != 1) && (Q('DeskControl').checked == true); }
448
- function clearConsoleMsg() { QH('p11DeskConsoleMsg', ''); }
837
+ function updateFooterMenu(options) {
838
+ while (options != null && options.length < 3) { options.push({ n: '' }); }
839
+ var x = '', prev = '';
840
+ if (options != null) { for (var i in options) { x += '<td style="cursor:pointer' + ((prev == '') ? '' : ';border-left:solid 1px white') + (options[i].s ? ';background-color:#487099' : '') + '" onclick="' + options[i].f + '">' + options[i].n; prev = options[i].n; } }
841
+ QH('footerMenu', '<tr>' + x);
842
+ }
843
450
- function deskAdjust() {
451
- if ((xxcurrentView == 12) && (terminal != null) && (xtermfit != null)) { xtermfit.fit(); } // Terminal
452
- QS('fileArea4')['height'] = 'calc(100vh - ' + (90 + Q('fileArea2').clientHeight) + 'px)'; // Files
844
454
- if (fullscreen) {
455
- QS('Desk')['margin-top'] = null;
456
- QS('Desk')['margin-bottom'] = null;
457
- QS('deskarea3x')['padding-right'] = '55px';
458
- QS('Desk').width = '100%';
459
- QS('Desk').height = '100%';
460
- var parentH = Q('p11').clientHeight, parentW = Q('p11').clientWidth;
461
- var deskH = Q('deskarea3x').clientHeight, deskW = Q('deskarea3x').clientWidth - 55;
462
- if (parentH > deskH) { QS('deskarea3x').top = ((parentH - deskH) / 2) + 'px'; } else { QS('deskarea3x').top = null; }
463
- if (parentW > deskW) { QS('deskarea3x').left = ((parentW - deskW) / 2) + 'px'; } else { QS('deskarea3x').left = null; }
464
- } else {
465
- var parentH = Q('DeskParent').clientHeight, parentW = Q('DeskParent').clientWidth;
466
- var deskH = Q('Desk').height, deskW = Q('Desk').width;
845
+ //
846
+ // MY DEVICES
847
+ //
848
468
- // Fixed aspect ratio
469
- if ((parentH / parentW) > (deskH / deskW)) {
470
- var hNew = ((deskH * parentW) / deskW) + 'px';
471
- QS('Desk').height = hNew;
472
- QS('Desk').width = '100%';
473
- } else {
474
- var wNew = ((deskW * parentH) / deskH) + 'px';
475
- QS('Desk').height = '100%';
476
- QS('Desk').width = wNew;
849
+ var gotKeyPressEvent = false;
850
+ function ondeskkeypress(e, t) {
851
+ setSessionActivity();
852
+ if (desktop && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 1)) {
853
+ gotKeyPressEvent = true;
854
+ Q('softKeyboard').value = '';
855
+ // Check what keys we are allows to send
856
+ if (currentNode != null) {
857
+ var meshrights = GetMeshRights(currentNode.meshid);
858
+ var inputAllowed = ((features2 & 0x2000) == 0) && ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
859
+ if (inputAllowed == false) return false;
860
+ var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
861
+ if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
862
}
478
- QS('Desk')['margin-top'] = null;
479
- QS('deskarea3x')['padding-right'] = null;
863
+ return desktop.m.handleKeys(e);
864
}
481
- }
482
-
483
- function setupDesktop() {
484
- // Setup the remote desktop
485
- if (desktop != null) { desktop.Stop(); desktop = null; }
486
-
487
- // If the device desktop is already connected in multi-desktop, use that.
488
- if (desktop == null) {
489
- // Device is not already connected, just setup a blank canvas
490
- QH('DeskParent', '<canvas id=Desk oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
491
-
492
- // Setup the mouse wheel
493
- Q('Desk').addEventListener('DOMMouseScroll', function (e) { return dmousewheel(e); });
494
- Q('Desk').addEventListener('mousewheel', function (e) { return dmousewheel(e); });
865
+ if (terminal && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 5) && (t !== 1)) {
866
+ if (e.altKey == true) { return true; }
867
+ gotKeyPressEvent = true;
868
+ Q('softKeyboard').value = '';
869
+ var k = 0;
870
+ if (e.charCode != 0) { k = e.charCode; } else if (e.keyCode != 0) { k = e.keyCode; }
871
+ if (k != 0) {
872
+ if (terminal.urlname == 'sshterminalrelay.ashx') {
873
+ // SSH
874
+ terminal.socket.send('~' + String.fromCharCode(k));
875
+ } else {
876
+ // Agent
877
+ terminal.sendText(String.fromCharCode(k));
878
+ }
879
+ }
880
+ return false;
881
}
496
- updateDesktopButtons();
497
- deskAdjust();
498
- updateMetadata(desktop, 'deskmetadata');
882
}
883
501
- // Show and enable the right buttons
502
- function updateDesktopButtons() {
503
- var deskState = 0;
504
- if (desktop != null) { deskState = desktop.State; }
505
-
506
- // Show the right buttons
507
- QV('disconnectbutton1span', (deskState != 0));
508
- QV('connectbutton1span', (deskState == 0) && (agentPresent));
509
- QV('connectbutton1hspan', (deskState == 0) && (intelAmtPresent));
510
-
511
- // Show the right settings
512
- QV('d7meshkvm', agentPresent && ((deskState == 0) || (desktop.contype == 1)));
513
- QV('d7amtkvm', intelAmtPresent && ((deskState == 0) || (desktop.contype == 2)));
514
-
884
+ function ondeskkeydown(e, t) {
885
+ setSessionActivity();
886
+ if (desktop && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 1)) {
887
+ gotKeyPressEvent = false;
888
+ Q('softKeyboard').value = '';
889
+ // Check what keys we are allows to send
890
+ if (currentNode != null) {
891
+ var meshrights = GetMeshRights(currentNode.meshid);
892
+ var inputAllowed = ((features2 & 0x2000) == 0) && ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
893
+ if (inputAllowed == false) return false;
894
+ var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
895
+ if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
896
+ }
897
+ return desktop.m.handleKeyDown(e);
898
+ }
899
+ if (terminal && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 5) && (t !== 1)) {
900
+ if (e.altKey == true) { return true; }
901
+ Q('softKeyboard').value = '';
902
+ gotKeyPressEvent = false;
903
+ var k = 0;
904
+ if (e.charCode != 0) { k = e.charCode; } else if (e.keyCode != 0) { k = e.keyCode; }
905
+ if (k == 8) { terminal.sendText(String.fromCharCode(k)); } // Enter and backspace
906
+ else if (e.ctrlKey && (k >= 64) && (k <= 95)) {
907
+ // Ctrl keys
908
+ if (terminal.urlname == 'sshterminalrelay.ashx') {
909
+ // SSH
910
+ terminal.socket.send('~' + String.fromCharCode(k - 64));
911
+ } else {
912
+ // Agent
913
+ terminal.sendText(String.fromCharCode(k - 64));
914
+ }
915
+ }
916
+ }
917
+ }
918
+
919
+ function ondeskkeyup(e, t) {
920
+ setSessionActivity();
921
+ if (desktop && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 1)) {
922
+ var inputStr = Q('softKeyboard').value;
923
+ Q('softKeyboard').value = '';
924
+ // Check what keys we are allows to send
925
+ if (currentNode != null) {
926
+ var meshrights = GetMeshRights(currentNode.meshid);
927
+ var inputAllowed = ((features2 & 0x2000) == 0) && ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
928
+ if (inputAllowed == false) return false;
929
+ var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
930
+ if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
931
+ }
932
+ if ((gotKeyPressEvent == false) && (inputStr.length > 0) && desktop.m.SendKeyUnicode) {
933
+ // This is a mobile keyboard, we need to send that is in the input control.
934
+ var inputchar = inputStr[inputStr.length - 1].charCodeAt(0);
935
+ desktop.m.SendKeyUnicode(desktop.m.KeyAction.DOWN, inputchar);
936
+ desktop.m.SendKeyUnicode(desktop.m.KeyAction.UP, inputchar);
937
+ } else {
938
+ return desktop.m.handleKeyUp(e);
939
+ }
940
+ }
941
+ if (terminal && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 5) && (gotKeyPressEvent == false) && (t !== 1)) {
942
+ if (e.altKey == true) { return true; }
943
+ var inputStr = Q('softKeyboard').value;
944
+ Q('softKeyboard').value = '';
945
+ if (terminal.urlname == 'sshterminalrelay.ashx') {
946
+ // SSH
947
+ terminal.socket.send('~' + inputStr);
948
+ } else {
949
+ // Agent
950
+ if (inputStr)
951
+ terminal.sendText(inputStr);
952
+ }
953
+ return false;
954
+ }
955
+ }
956
+
957
+
958
+ //
959
+ // MY DEVICE
960
+ //
961
+
962
+ var currentDevicePanel = 0;
963
+ function setupDeviceMenu(op, obj) {
964
+ if (op != null) { currentDevicePanel = op; }
965
+ QV('p10desktop', currentDevicePanel == 1); // Show if we have remote control rights or desktop view only rights
966
+ QV('p10files', currentDevicePanel == 2);
967
+ QV('p10terminal', currentDevicePanel == 5);
968
+ var menus = [];
969
+ if (features & 2) { menus.push({ n: "Desktop", f: 'setupDeviceMenu(1)', s: (currentDevicePanel == 1) }); }
970
+ if (features & 1) { menus.push({ n: "Terminal", f: 'setupDeviceMenu(5)', s: (currentDevicePanel == 5) }); }
971
+ if (features & 4) { menus.push({ n: "Files", f: 'setupDeviceMenu(2)', s: (currentDevicePanel == 2) }); }
972
+ updateFooterMenu(menus);
973
+ if (currentDevicePanel == 1) { deskAdjust(); }
974
+
975
+ /*
976
+ var meshrights = GetNodeRights(currentNode);
977
+ if (op != null) { currentDevicePanel = op; }
978
+ QV('p10general', currentDevicePanel == 0);
979
+ QV('p10desktop', currentDevicePanel == 1); // Show if we have remote control rights or desktop view only rights
980
+ QV('p10files', currentDevicePanel == 2);
981
+ QV('p10details', currentDevicePanel == 3);
982
+ QV('p10console', currentDevicePanel == 4);
983
+ QV('p10terminal', currentDevicePanel == 5);
984
+ var menus = [];
985
+ if (currentDevicePanel != 0) { menus.push({ n: "General", f: 'setupDeviceMenu(0)' }); }
986
+
987
+ if ((currentDevicePanel != 1) &&
988
+ (currentNode != null) &&
989
+ ((meshrights & 8) || (meshrights & 256)) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 65536) == 0)) &&
990
+ (((currentNode.agent == null) && (currentNode.intelamt) && ((typeof currentNode.intelamt.sku !== 'number') || ((currentNode.intelamt.sku & 8) != 0))) || (currentNode.agent && (currentNode.agent.caps & 1)))
991
+ ) { menus.push({ n: "Desktop", f: 'setupDeviceMenu(1)' }); }
992
+
993
+ if ((currentDevicePanel != 5) &&
994
+ (currentNode != null) &&
995
+ ((meshrights & 8) || (meshrights & 256)) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0)) &&
996
+ (((currentNode.agent == null) && (currentNode.intelamt) && ((typeof currentNode.intelamt.sku !== 'number') || ((currentNode.intelamt.sku & 8) != 0))) || (currentNode.agent && (currentNode.agent.caps & 2)))
997
+ ) { menus.push({ n: "Terminal", f: 'setupDeviceMenu(5)' }); }
998
+
999
+ if ((currentDevicePanel != 2) && (currentNode != null) && (meshrights & 8) && ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0)) && ((currentNode.mtype != 1) && (currentNode.agent) && (currentNode.agent.caps & 4))) { menus.push({ n: "Files", f: 'setupDeviceMenu(2)' }); }
1000
+ if ((currentDevicePanel != 3) && (currentNode != null) && (currentNode.mtype < 3) && ((meshrights & 1048576) != 0)) { menus.push({ n: "Details", f: 'setupDeviceMenu(3)' }); }
1001
+ if ((currentDevicePanel != 4) && (currentNode != null) && (meshrights & 0x00000010) && (currentNode.mtype == 2)) { menus.push({ n: "Console", f: 'setupDeviceMenu(4)' }); }
1002
+
1003
+ updateFooterMenu(menus);
1004
+ if (currentDevicePanel == 1) { deskAdjust(); }
1005
+ */
1006
+ }
1007
+
1008
+
1009
+ //
1010
+ // DESKTOP
1011
+ //
1012
+
1013
+ var desktop;
1014
+ var desktopNode;
1015
+ var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50, autolock: false };
1016
+ function setupDesktop() {
1017
+ // Setup the remote desktop
1018
+ if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); desktopNode = null; desktop = null; }
1019
+
1020
+ // If the device desktop is already connected in multi-desktop, use that.
1021
+ if ((desktopNode != currentNode) || (desktop == null)) {
1022
+ // Device is not already connected, just setup a blank canvas
1023
+ //QH('DeskParent', '<canvas id=Desk width=640 height=200 style="width:100%;-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
1024
+ desktopNode = currentNode;
1025
+ // Setup the mouse wheel
1026
+ Q('Desk').addEventListener('DOMMouseScroll', function (e) { return dmousewheel(e); });
1027
+ Q('Desk').addEventListener('mousewheel', function (e) { return dmousewheel(e); });
1028
+ }
1029
+ desktopNode = currentNode;
1030
+ updateDesktopButtons();
1031
+
1032
+ // On some browsers like IE, we can't save screen shots. Hide the scheenshot/capture buttons.
1033
+ if (!Q('Desk')['toBlob']) { QV('deskSaveBtn', false); }
1034
+ }
1035
+
1036
+ // Show and enable the right buttons
1037
+ function updateDesktopButtons() {
1038
+ var mesh = meshes[currentNode.meshid];
1039
+ var deskState = 0;
1040
+ if (desktop != null) { deskState = desktop.State; }
1041
+ var meshrights = GetNodeRights(currentNode);
1042
+
1043
+ // Show the right buttons
1044
+ QV('disconnectbutton1', (deskState != 0));
1045
+ QE('deskFullScreen', (deskState != 0));
1046
+ QV('connectbutton1', (deskState == 0) && ((meshrights & 8) || (meshrights & 256)) && (currentNode.agent != null) && (currentNode.agent.caps & 1));
1047
+ QV('connectbutton1h',
1048
+ (deskState == 0) &&
1049
+ (meshrights & 8) &&
1050
+ (
1051
+ ((currentNode.intelamt != null) &&
1052
+ (currentNode.intelamt.state == 2) &&
1053
+ (currentNode.intelamt.ver != null) &&
1054
+ ((currentNode.intelamt.sku == null) ||
1055
+ ((typeof currentNode.intelamt.sku == 'number') &&
1056
+ ((currentNode.intelamt.sku & 8) != 0))))
1057
+ )
1058
+ );
1059
+
1060
+ // Show the right settings
1061
+ QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (currentNode.agent == null))) && ((deskState == 0) || (desktop.contype == 2)));
1062
+ QV('d7meshkvm', ((currentNode.agent != null) && (currentNode.agent.caps & 1) && ((deskState == false) || (desktop.contype == 1))));
1063
+
1064
// Enable buttons
516
- QE('connectbutton1', agentPresent);
517
- QE('connectbutton1h', intelAmtPresent);
518
- //QV('DeskClip', agentPresent && ((desktop == null) || (desktop.contype != 2))); // Clipboard not supported on macOS
519
- QV('DeskClip', false); // Clipboard not supported on this page
520
- QE('DeskClip', deskState == 3);
521
- QE('DeskType', deskState == 3);
522
- QV('DeskWD', viewOnly != 1);
523
- QE('DeskWD', deskState == 3);
524
- QV('deskkeys', viewOnly != 1);
525
- QE('deskkeys', deskState == 3);
526
-
527
- // Display this only if we have Chat & Notify permissions
528
- QV('DeskSaveImageButton', (deskState == 3) && (Q('Desk')['toBlob'] != null));
529
- QV('DeskControlSpan', viewOnly != 1);
530
- QV('deskActionsBtn', true);
531
- QV('deskActionsSettings', (deskState != 3));
532
- Q('DeskControl').checked = true;
533
- QS('DeskControlSpan').color = Q('DeskControl').checked ? null : 'red';
1065
+ var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
1066
+ QE('connectbutton1', online);
1067
+ var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
1068
+ QE('connectbutton1h', hwonline);
1069
+ //QE('deskSaveBtn', deskState == 3);
1070
+ //QV('DeskCAD', meshrights & 8);
1071
+ //QE('DeskCAD', deskState == 3);
1072
+ //QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5));
1073
+ //QE('DeskWD', deskState == 3);
1074
+ //QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5));
1075
+ //QE('deskkeys', deskState == 3);
1076
+ //QE('DeskToolsButton', online);
1077
+ QV('DeskToastButton', ((meshrights & 16384) != 0) && (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8));
1078
+ //QE('DeskToastButton', online);
1079
+ QV('deskActionsBtn', meshrights & 8);
1080
+ Q('DeskControl').checked = ((meshrights & 8) != 0);
1081
+ if (online == false) QV('DeskTools', false);
1082
}
1083
1084
// Used to translate incoming agent console messages
@@ -544,108 +1092,35 @@
1092
}
1093
1094
function connectDesktop(e, contype, tsid, consent) {
547
- if (xxdialogMode) return;
548
- if ((e != null) && (e.shiftKey != false) && (contype == 3)) { contype = 1; } // If the shift key is not pressed, don't try to ask for session list.
1095
+ setSessionActivity();
1096
QV('p11DeskSessionSelector', false);
1097
p11clearConsoleMsg();
1098
if (desktop == null) {
1099
+ desktopNode = currentNode;
1100
if (contype == 2) {
1101
// Setup the Intel AMT remote desktop
554
- //if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop, 2); return; }
1102
+ if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
1103
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
1104
desktop.debugmode = debugmode;
1105
desktop.onStateChanged = onDesktopStateChange;
558
- desktop.m.stopInput = (viewOnly == 1);
1106
desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
1107
desktop.m.useZRLE = (desktopsettings.encoding < 3);
561
- desktop.m.localKeyMap = desktopsettings.localkeymap;
562
- desktop.m.showmouse = desktopsettings.showmouse;
563
- desktop.m.onScreenSizeChange = deskAdjust;
564
- desktop.m.onKvmData = function (x) {
565
- //console.log('onKvmData (' + x.length + '): ' + x);
566
- // Send the presense probe only once if needed.
567
- if (x.length == 0) { if (!desktop.m._sentPresence) { desktop.m._sentPresence = true; desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 })); } return; }
568
- var data = null;
569
- try { data = JSON.parse(x); } catch (e) { }
570
- if ((data != null) && (data.action != null)) {
571
- if (data.action == 'restart') {
572
- // Clear WebRTC channel
573
- webRtcDesktopReset();
574
- desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 }));
575
- } else if ((data.action == 'present') && (webRtcDesktop == null)) {
576
- // Setup WebRTC channel
577
- webRtcDesktop = { platform: data.platform };
578
- var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };
579
- if (typeof RTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new RTCPeerConnection(configuration); }
580
- else if (typeof webkitRTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new webkitRTCPeerConnection(configuration); }
581
-
582
- webRtcDesktop.webchannel = webRtcDesktop.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
583
- webRtcDesktop.webchannel.onopen = function () {
584
- // Switch to software KVM
585
- //if (urlvars && urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Open'); }
586
- console.log('WebRTC Data Channel Open');
587
- Q('deskstatus').textContent = StatusStrs[desktop.State] + ", Soft-KVM";
588
- desktop.m.hold(true);
589
- webRtcDesktop.webRtcActive = true;
590
- webRtcDesktop.softdesktop = CreateKvmDataChannel(webRtcDesktop.webchannel, CreateAgentRemoteDesktop('Desk', Q('id_mainarea')), desktop.m);
591
- webRtcDesktop.softdesktop.m.setRotation(desktop.m.rotation);
592
- webRtcDesktop.softdesktop.m.onScreenSizeChange = deskAdjust;
593
- if (desktopsettings.quality) { webRtcDesktop.softdesktop.m.CompressionLevel = desktopsettings.quality; } // Number from 1 to 100. 50 or less is best.
594
- if (desktopsettings.scaling) { webRtcDesktop.softdesktop.m.ScalingLevel = desktopsettings.scaling; }
595
- webRtcDesktop.softdesktop.Start();
596
-
597
- // Check if we can get remote file access
598
- // ###BEGIN###{DesktopInbandFiles}
599
- /*
600
- QV('go24', true); // Files
601
- downloadFile = null;
602
- p24files = webRtcDesktop.softdesktop;
603
- p24targetpath = '';
604
- webRtcDesktop.softdesktop.onControlMsg = onFilesControlData;
605
- webRtcDesktop.softdesktop.sendCtrlMsg(JSON.stringify({ action: 'ls', reqid: 1, path: '' })); // Ask for the root folder
606
- */
607
- // ###END###{DesktopInbandFiles}
608
- }
609
- webRtcDesktop.webchannel.onclose = function (event) {
610
- //if (urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Closed'); }
611
- console.log('WebRTC Data Channel Closed');
612
- webRtcDesktopReset();
613
- }
614
- webRtcDesktop.webrtc.onicecandidate = function (e) {
615
- if (e.candidate == null) {
616
- desktop.m.sendKvmData(JSON.stringify({ action: 'offer', ver: 1, sdp: webRtcDesktop.webrtcoffer.sdp }));
617
- } else {
618
- webRtcDesktop.webrtcoffer.sdp += ('a=' + e.candidate.candidate + '\r\n'); // New candidate, add it to the SDP
619
- }
620
- }
621
- webRtcDesktop.webrtc.oniceconnectionstatechange = function () {
622
- if ((webRtcDesktop != null) && (webRtcDesktop.webrtc != null) && ((webRtcDesktop.webrtc.iceConnectionState == 'disconnected') || (webRtcDesktop.webrtc.iceConnectionState == 'failed'))) { /*console.log('WebRTC ICE Failed');*/ webRtcDesktopReset(); }
623
- }
624
- webRtcDesktop.webrtc.createOffer(function (offer) {
625
- // Got the offer
626
- webRtcDesktop.webrtcoffer = offer;
627
- webRtcDesktop.webrtc.setLocalDescription(offer, function () { }, webRtcDesktopReset);
628
- }, webRtcDesktopReset, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
629
- } else if ((data.action == 'answer') && (webRtcDesktop != null)) {
630
- // Complete the WebRTC channel
631
- webRtcDesktop.webrtc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: data.sdp }), function () { }, webRtcDesktopReset);
632
- }
633
- }
634
- };
635
- desktop.Start(null, 16994, '*', '*', 0);
1108
+ desktop.m.showmouse = true;
1109
+ desktop.m.onScreenSizeChange = function (o, x, y) { if (fullscreen) { QS('deskarea3').width = (x * fullscreenzoom) + 'px'; QS('deskarea3').height = (y * fullscreenzoom) + 'px'; } deskAdjust(); }
1110
+ desktop.Start(desktopNode._id, 16994, '*', '*', 0);
1111
desktop.contype = 2;
637
- } else if ((contype == null) || (contype == 1) || (contype == 3)) {
1112
+ } else if ((contype == null) || (contype == 1) || ((contype == 3) && (currentNode.agent.id > 4))) {
1113
// Setup the Mesh Agent remote desktop
639
- desktop = CreateAgentRedirect(null, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, null, domainUrl);
640
- desktop.m.stopInput = (viewOnly == 1);
641
- desktop.m.mouseCursorActive(true);
1114
+ desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
1115
desktop.debugmode = debugmode;
1116
desktop.m.debugmode = debugmode;
1117
desktop.attemptWebRTC = attemptWebRTC;
1118
desktop.options = {};
1119
if (tsid != null) { desktop.options.tsid = tsid; }
1120
if (consent != null) { desktop.options.consent = consent; }
1121
+ if (desktopsettings.autolock == true) { desktop.options.autolock = true; }
1122
desktop.onStateChanged = onDesktopStateChange;
1123
+ if ((features2 & 0x2000) != 0) desktop.m.stopInput = true;
1124
desktop.onConsoleMessageChange = function () {
1125
if (desktop.consoleMessage) {
1126
Q('p11DeskConsoleMsg').innerHTML += formatAgentConsoleMessage(desktop.consoleMessage, desktop.consoleMessageId, desktop.consoleMessageArgs);
@@ -656,52 +1131,22 @@
1131
p11clearConsoleMsg();
1132
}
1133
}
659
- desktop.onMetadataChange = function (metadata) { updateMetadata(desktop, 'deskmetadata'); }
1134
+ desktop.m.ImageType = webpSupport ? 4 : 1; // Send 4 if WebP is supported, otherwise send 1 for JPEG.
1135
desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
1136
desktop.m.ScalingLevel = desktopsettings.scaling;
662
- if (desktopsettings.framerate) { desktop.m.FrameRateTimer = desktopsettings.framerate; }
1137
+ desktop.m.FrameRateTimer = desktopsettings.framerate;
1138
desktop.m.onDisplayinfo = deskDisplayInfo;
664
- desktop.m.onScreenSizeChange = deskAdjust;
665
- desktop.Start(null);
666
- desktop.latency.callback = function (ms) { console.log('latency', ms); updateSessionTime(); };
1139
+ desktop.m.onScreenSizeChange = function (o, x, y) { if (fullscreen) { QS('deskarea3').width = (x * fullscreenzoom) + 'px'; QS('deskarea3').height = (y * fullscreenzoom) + 'px'; } deskAdjust(); }
1140
+ desktop.Start(desktopNode._id);
1141
desktop.contype = 1;
1142
+ } else if (contype == 3) {
1143
+ // Ask for user sessions
1144
+ meshserver.send({ action: 'msg', type: 'userSessions', nodeid: currentNode._id, tag: consent });
1145
}
1146
} else {
1147
// Disconnect and clean up the remote desktop
1148
desktop.Stop();
672
- webRtcDesktopReset();
673
- desktop = null;
674
- //if (pluginHandler != null) { pluginHandler.callHook('onDesktopDisconnect'); }
675
- }
676
- }
677
-
678
- function updateMetadata(conn, elementid) {
679
- var str = '', viewerCount = 0;
680
- if (conn && (conn.State == 3)) {
681
- if (conn.metadata && conn.metadata.users) { for (var i in conn.metadata.users) { viewerCount += conn.metadata.users[i]; } }
682
- if (viewerCount > 1) { str = '<span onclick=showSessionMetadata(1) style=cursor:pointer>' + format(", {0} watching", viewerCount) + '</span>'; }
683
- }
684
- QH('deskmetadata', str);
685
- if ((conn == desktop) && (xxdialogTag == ('sessionMetadata1'))) { showSessionMetadata(1); }
686
- }
687
-
688
- function showSessionMetadata(cid) {
689
- if (xxdialogMode && (xxdialogTag != ('sessionMetadata' + cid))) return;
690
- if (xxdialogMode) { setDialogMode(0); }
691
- var conn = null;
692
- if (cid == 1) { conn = desktop; }
693
- if (conn && conn.metadata) {
694
- var x = '';
695
- if (conn.metadata.startTime) { x += addHtmlValue4("Start Time", printDateTime(new Date(conn.metadata.startTime))); }
696
- if (conn.metadata.users) {
697
- for (var i in conn.metadata.users) {
698
- var val = (conn.metadata.users[i] == 1) ? "1 connection" : format("{0} connections", conn.metadata.users[i]);
699
- var username = i.split('/')[2];
700
- if ((users != null) && (users[i] != null)) { username = users[i].name; }
701
- x += addHtmlValue4(format("User \"{0}\"", username), val);
702
- }
703
- }
704
- setDialogMode(2, "Session Information", 1, null, x, 'sessionMetadata' + cid);
1149
+ desktopNode = desktop = null;
1150
}
1151
}
1152
@@ -709,27 +1154,26 @@
1154
function p12clearConsoleMsg() { QH('p12TermConsoleMsg', ''); QV('p12TermConsoleMsg', false); if (p12TermConsoleMsgTimer) { clearTimeout(p12TermConsoleMsgTimer); p12TermConsoleMsgTimer = null; } }
1155
function p13clearConsoleMsg() { QH('p13FilesConsoleMsg', ''); QV('p13FilesConsoleMsg', false); if (p13FilesConsoleMsgTimer) { clearTimeout(p13FilesConsoleMsgTimer); p13FilesConsoleMsgTimer = null; } }
1156
712
- var webRtcDesktop = null;
713
- function webRtcDesktopReset() {
714
- if (webRtcDesktop == null) return;
715
- if (webRtcDesktop.softdesktop != null) { webRtcDesktop.softdesktop.Stop(); webRtcDesktop.softdesktop = null; }
716
- if (webRtcDesktop.webchannel != null) { try { webRtcDesktop.webchannel.close(); } catch (e) { } webRtcDesktop.webchannel = null; }
717
- if (webRtcDesktop.webrtc != null) { try { webRtcDesktop.webrtc.close(); } catch (e) { } webRtcDesktop.webrtc = null; }
718
- webRtcDesktop = null;
719
- // Switch back to hardware KVM
720
- if (desktop && desktop.m) {
721
- desktop.m.hold(false);
722
- Q('deskstatus').textContent = StatusStrs[desktop.State];
1157
+ function p12setConsoleMsg(msg, timeout) {
1158
+ if (msg) {
1159
+ Q('p12TermConsoleMsg').innerHTML += msg;
1160
+ QV('p12TermConsoleMsg', true);
1161
+ if (p12TermConsoleMsgTimer != null) { clearTimeout(p12TermConsoleMsgTimer); }
1162
+ if (timeout) { p12TermConsoleMsgTimer = setTimeout(p12clearConsoleMsg, timeout); }
1163
+ } else {
1164
+ p12clearConsoleMsg();
1165
+ }
1166
+ }
1167
+
1168
+ function p13setConsoleMsg(msg, timeout) {
1169
+ if (msg) {
1170
+ Q('p13FilesConsoleMsg').innerHTML += msg;
1171
+ QV('p13FilesConsoleMsg', true);
1172
+ if (p13FilesConsoleMsgTimer != null) { clearTimeout(p13FilesConsoleMsgTimer); }
1173
+ if (timeout) { p13FilesConsoleMsgTimer = setTimeout(p13clearConsoleMsg, timeout); }
1174
+ } else {
1175
+ p13clearConsoleMsg();
1176
}
724
- // ###BEGIN###{DesktopInbandFiles}
725
- /*
726
- p24files = null;
727
- p24downloadFileCancel() // If any downloads are in process, cancel them.
728
- p24uploadFileCancel(); // If any uploads are in process, cancel them.
729
- QV('go24', false); // Files
730
- if (currentView == 24) { go(14); }
731
- */
732
- // ###END###{DesktopInbandFiles}
1177
}
1178
1179
function onDesktopStateChange(xdesktop, state) {
@@ -739,29 +1183,16 @@
1183
if ((desktop != null) && (desktop.webRtcActive == true)) { str += ", WebRTC"; }
1184
//if (desktop.m.stopInput == true) { str += ', Loopback'; }
1185
QH('deskstatus', str);
742
- QV('deskFullScreen', state == 3);
743
- QV('deskActionsSettings', state != 3);
1186
switch (state) {
1187
case 0:
746
- // Stop recording
747
- if (desktop.m.recordedData != null) { deskRecordSession(); }
748
-
1188
// Disconnect and clean up the remote desktop
1189
desktop.Stop();
751
- desktop = null;
752
- QV('termdisplays', false);
753
- QV('deskRecordIcon', false);
1190
+ desktopNode = desktop = null;
1191
+ QV('DeskScreens', false);
1192
if (fullscreen == true) { deskToggleFull(); }
755
- webRtcDesktopReset();
756
- deskPreferedStickyDisplay = 0;
1193
break;
1194
case 2:
1195
break;
760
- case 3:
761
- if (desktop && (desktop.serverIsRecording == true)) { QV('deskRecordIcon', true); }
762
- desktop.startTime = new Date();
763
- if (updateSessionTimer == null) { updateSessionTimer = setInterval(updateSessionTime, 1000); }
764
- break;
1196
default:
1197
//console.log('Unknown onDesktopStateChange state', state);
1198
break;
@@ -769,21 +1200,6 @@
1200
updateDesktopButtons();
1201
deskAdjust();
1202
setTimeout(deskAdjust, 50);
772
- updateMetadata(desktop, 'deskmetadata');
773
- }
774
-
775
- function updateSessionTime() {
776
- // Desktop
777
- var latencyStr = '', seconds = 0;
778
- if (desktop && desktop.startTime) {
779
- if (desktop.latency && (desktop.latency.current >= 0)) { latencyStr = format('{0} ms, ', desktop.latency.current); }
780
- seconds = Math.floor((new Date() - desktop.startTime) / 1000);
781
- QH('DeskTimer', latencyStr + zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2));
782
- } else {
783
- QH('DeskTimer', '');
784
- }
785
-
786
- if (desktop == null) { clearInterval(updateSessionTimer); updateSessionTimer = null; }
1203
}
1204
1205
function showDesktopSettings() {
@@ -798,18 +1214,13 @@
1214
desktopsettings.quality = d7bitmapquality.value;
1215
desktopsettings.scaling = d7bitmapscaling.value;
1216
desktopsettings.framerate = d7framelimiter.value;
801
- desktopsettings.swapmouse = d7deskSwapMouse.checked;
802
- desktopsettings.remotekeymap = d7deskRemoteKeyMap.checked;
803
- desktopsettings.localkeymap = d7localKeyMap.checked;
1217
+ desktopsettings.autolock = d7deskAutoLock.checked;
1218
localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
1219
applyDesktopSettings();
1220
if (desktop) {
1221
if (desktop.contype == 1) {
808
- desktop.m.SwapMouse = desktopsettings.swapmouse;
809
- desktop.m.remoteKeyMap = desktopsettings.remotekeymap;
810
- if (desktop.State != 0) {
811
- desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate);
812
- }
1222
+ if (desktop.State != 0) { desktop.m.SendCompressionLevel(webpSupport ? 4 : 1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
1223
+ desktop.sendCtrlMsg('{"ctrlChannel":"102938","type":"autolock","value":' + desktopsettings.autolock + '}');
1224
}
1225
if (desktop.contype == 2) {
1226
if (desktop.State != 0) { desktop.Stop(); setTimeout(function () { connectDesktop(null, 2); }, 50); }
@@ -818,713 +1229,475 @@
1229
}
1230
1231
function applyDesktopSettings() {
821
- var r = '', ops = (features2 & 1) ? [90, 80, 70, 60, 50, 40, 30, 20, 10, 5, 1] : [60, 50, 40, 30, 20, 10, 5, 1]
1232
+ var r = '', ops = (features & 512) ? [90, 70, 50, 40, 30, 20, 10, 5, 1] : [50, 40, 30, 20, 10, 5, 1];
1233
for (var i in ops) { r += '<option value=' + ops[i] + '>' + ops[i] + '%</option>'; }
1234
QH('d7bitmapquality', r);
1235
d7desktopmode.value = desktopsettings.encoding;
1236
d7bitmapquality.value = 40; // Default value
1237
if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
1238
d7bitmapscaling.value = desktopsettings.scaling;
828
- if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; } else { d7framelimiter.value = 100; }
829
- if (desktopsettings.swapmouse != null) { d7deskSwapMouse.checked = desktopsettings.swapmouse; }
830
- if (desktopsettings.remotekeymap != null) { d7deskRemoteKeyMap.checked = desktopsettings.remotekeymap; }
831
- if (desktopsettings.localkeymap) { d7localKeyMap.checked = desktopsettings.localkeymap; }
1239
+ if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; }
1240
+ if (desktopsettings.autolock != null) { d7deskAutoLock.checked = desktopsettings.autolock; }
1241
}
1242
834
- function toggleMenu(x) {
1243
+
1244
+ var keyboardShown = false;
1245
+ var keyboardShownTimer = null;
1246
+ var fullScreenMode = false;
1247
+ function toggleKeyboard() {
1248
if (xxdialogMode) return;
836
- QV('deskButtonMenu', fullscreen && !x && (xxcurrentView == 11));
837
- QV('termButtonMenu', fullscreen && !x && (xxcurrentView == 12));
838
- QV('deskkeybutton3a', fullscreen && x);
839
- QV('deskkeybutton3b', fullscreen && !x);
1249
+ if (keyboardShownTimer != null) { clearTimeout(keyboardShownTimer); }
1250
+ if (keyboardShown) { Q('softKeyboard').blur(); keyboardShown = false; } else { Q('softKeyboard').focus(); keyboardShown = true; }
1251
+ QV('deskkeybutton2a', fullscreen && !keyboardShown);
1252
+ QV('deskkeybutton2b', fullscreen && keyboardShown);
1253
}
1254
842
- function deskChangeMouseButton(x) {
843
- if (xxdialogMode) return;
844
- if (desktop == null) return;
845
- desktop.m.SwapMouse = !desktop.m.SwapMouse;
846
- QV('deskkeybutton4a', fullscreen && (!desktop.m.SwapMouse));
847
- QV('deskkeybutton4b', fullscreen && (desktop.m.SwapMouse));
1255
+ function keyboardFocusChange() {
1256
+ keyboardShownTimer = setTimeout(function () {
1257
+ keyboardShownTimer = null;
1258
+ keyboardShown = (Q('softKeyboard') == document.activeElement);
1259
+ QV('deskkeybutton2a', fullscreen && !keyboardShown);
1260
+ QV('deskkeybutton2b', fullscreen && keyboardShown);
1261
+ }, 10);
1262
}
1263
850
- function deskChangeFullscreenZoom() {
1264
+ function exitButton() {
1265
if (xxdialogMode) return;
852
- if (xxcurrentView == 11) {
853
- if (desktop == null) return;
854
- if (fullscreenzoom == 1) { fullscreenzoom = 0.5; } else { fullscreenzoom = 1; }
855
- QV('deskkeybutton5a', fullscreen && (fullscreenzoom == 1));
856
- QV('deskkeybutton5b', fullscreen && (fullscreenzoom != 1));
857
- QS('deskarea3x').width = (desktop.m.ScreenWidth * fullscreenzoom) + 'px';
858
- QS('deskarea3x').height = (desktop.m.ScreenHeight * fullscreenzoom) + 'px';
859
- deskAdjust();
860
- }
861
- if (xxcurrentView == 12) {
862
- if (terminal == null) return;
863
- xterm.setOption('fontSize', (xterm.getOption('fontSize') == 15) ? 10 : 15)
864
- }
1266
+ QV('deskButtonMenu', false);
1267
+ QV('termButtonMenu', false);
1268
+ deskToggleFull();
1269
}
1270
867
- var fullscreen = false;
868
- var fullscreenzoom = 1;
869
- function deskToggleFull(e) {
870
- var xtermActive = !((urlargs.xterm === 0) || ((terminal != null) && (xterm == null)));
871
- fullscreen = !fullscreen;
872
- if (fullscreen) {
873
- QV('deskarea1', false);
874
- QV('deskarea4', false);
875
- QV('xfooter', false);
876
- QS('p11').bottom = '0px';
877
- QS('deskarea0').overflow = 'scroll';
878
- QS('deskarea3x').width = (desktop.m.ScreenWidth * fullscreenzoom) + 'px';
879
- QS('deskarea3x').height = QS('deskarea3x')['max-height'] = (desktop.m.ScreenHeight * fullscreenzoom) + 'px';
880
- QS('deskarea3x')['padding-right'] = '55px';
881
- if (xtermActive) {
882
- // XTerm terminal
883
- //QS('termTable')['position'] = 'absolute';
884
- //QS('termTable')['top'] = QS('termTable')['bottom'] = QS('termTable')['left'] = QS('termTable')['right'] = '0';
885
- } else {
886
- // Legacy terminal
887
- //QS('termTable')['height'] = '100%';
888
- //QS('termTable')['max-height'] = '100%';
889
- }
890
- } else {
891
- QV('deskarea1', true);
892
- QV('deskarea4', true);
893
- QV('xfooter', true);
894
- QS('p11').bottom = '32px';
895
- QS('deskarea0').overflow = null;
896
- QS('deskarea3x').width = null;
897
- QS('deskarea3x').height = QS('deskarea3x')['max-height'] = 'calc(100vh - 60px)';
898
- QS('deskarea3x')['padding-right'] = null;
899
- if (xtermActive) {
900
- // XTerm terminal
901
- //QS('termTable')['position'] = null;
902
- //QS('termTable')['top'] = QS('termTable')['bottom'] = QS('termTable')['left'] = QS('termTable')['right'] = null;
903
- } else {
904
- // Legacy terminal
905
- //QS('termTable')['height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
906
- //QS('termTable')['max-height'] = 'calc(100vh - ' + (75 + xh) + 'px)';
907
- }
908
- }
1271
+ function deskMenuButton(x) {
1272
+ toggleMenu(true);
1273
+ deskSendKeys(x);
1274
+ }
1275
910
- inputAllowed = true; // todo
1276
+ //
1277
+ // Desktop Shortcut Keys
1278
+ //
1279
912
- // Show full screen buttons if needed
913
- QV('deskkeybutton1', fullscreen);
914
- if (xxcurrentView == 11) { // Desktop panel is being shown (11 = Desktop, 12 = Terminal)
915
- // Move shortcut key to desktop position
916
- QS('deskkeybutton2a').top = QS('deskkeybutton2b').top = '210px';
917
- // Move the zoom button to normal or top position
918
- QS('deskkeybutton5a').top = QS('deskkeybutton5b').top = (inputAllowed) ? '160px' : '60px'; // Zoom
919
- QV('deskkeybutton2a', fullscreen && inputAllowed);
920
- QV('deskkeybutton2b', false);
921
- QV('deskkeybutton3a', fullscreen && inputAllowed);
922
- QV('deskkeybutton3b', false);
923
- QV('deskkeybutton4a', fullscreen && inputAllowed && (!desktop.m.SwapMouse));
924
- QV('deskkeybutton4b', fullscreen && inputAllowed && (desktop.m.SwapMouse));
925
- QV('deskkeybutton5a', fullscreen && (fullscreenzoom == 1));
926
- QV('deskkeybutton5b', fullscreen && (fullscreenzoom != 1));
927
- }
928
- if (xxcurrentView == 12) {
929
- // Move right buttons to terminal position
930
- //QS('deskkeybutton3a').top = QS('deskkeybutton3b').top = '60px'; // Shortcuts
931
- //QS('deskkeybutton5a').top = QS('deskkeybutton5b').top = '110px'; // Zoom
932
- QS('deskkeybutton2a').top = QS('deskkeybutton2b').top = '110px'; // Keyboard
933
- QV('deskkeybutton2a', fullscreen);
934
- QV('deskkeybutton2b', false);
935
- QV('deskkeybutton3a', fullscreen);
936
- QV('deskkeybutton3b', false);
937
- QV('deskkeybutton4a', false);
938
- QV('deskkeybutton4b', false);
939
- QV('deskkeybutton5a', false);
940
- QV('deskkeybutton5a', false);
941
- //QV('deskkeybutton5a', xterm.getOption('fontSize') == 15);
942
- //QV('deskkeybutton5b', xterm.getOption('fontSize') != 15);
943
- }
1280
+ function updateDeskShortcutKeys() {
1281
+ var x = '<div class="menuButton" onclick="deskMenuButton(-1)">' + "Customize" + '</div>';
1282
+ for (var i in deskKeyboardShortcuts) { x += '<div class="menuButton" onclick="deskMenuButton(' + deskKeyboardShortcuts[i] + ')">' + keyShortcutTotext(deskKeyboardShortcuts[i]) + '</div>'; }
1283
+ QH('deskButtonMenu', x);
1284
+ }
1285
945
- if (xxcurrentView == 11) { deskAdjust(); }
946
- updateDesktopButtons();
947
- //adjustPanels();
948
- //setTimeout(adjustPanels, 10);
949
- //setTimeout(function() { xtermfit.fit(); }, 10);
950
- if (xterm != null) { if (xxcurrentView == 12) { xtermfit.fit(); xterm.focus(); } }
1286
+ var keyStrings = { 8: "BackSpace", 9: "Tab", 13: "Enter", 27: "Escape", 44 : "Print Screen", 45: "Insert", 46: "Del", 36: "Home", 35: "End", 33: "Page Up", 34: "Page Down", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 0: "None" }
1287
+
1288
+ function keyShortcutTotext(n) {
1289
+ var x = [];
1290
+ if (n & 0x010000) { x.push("Shift"); }
1291
+ if (n & 0x020000) { x.push("Alt"); }
1292
+ if (n & 0x080000) { x.push("Ctrl"); }
1293
+ if (n & 0x100000) { x.push("Win"); }
1294
+ n = (n & 0xFFFF);
1295
+ if ((n >= 112) && (n <= 123)) { x.push('F' + (n - 111)); } // Fx keys
1296
+ else if ((n != 0) && (keyStrings[n])) { x.push(keyStrings[n]); }
1297
+ else { if (n != 0) { x.push(String.fromCharCode(n)); } }
1298
+ return x.join(' + ');
1299
}
1300
953
- function mdeskAdjust(mod, sw, sh, cv) {
954
- if (!mod || !sw || !sh || !cv) return;
1301
+ // Customize keyboard shortcuts
1302
+ function deskCustomizeKeys() {
1303
+ if (xxdialogMode) return;
1304
+ var x = '<div id=d2shortcuts style="width:100%;height:180px;padding:4px;overflow-y:auto;border:1px solid gray"></div><div style=width:100%;padding:5px>';
1305
+ x += '<label><input id=d1kshift type=checkbox /> ' + "Shift" + '</label><label> <input id=d1kalt type=checkbox /> ' + "Alt" + '</label><label> <input id=d1kctrl type=checkbox /> ' + "Ctrl" + '</label> <input id=d1kwin type=checkbox /> ' + "Win" + '</label>';
1306
+ x += ' <select id=d2keySelect>';
1307
+ for (var i in keyStrings) { x += '<option value=' + i + '>' + keyStrings[i] + '</option>'; }
1308
+ for (var i = 1; i <= 12; i++) { x += '<option value=' + (i + 111) + '>F' + i + '</option>'; }
1309
+ for (var i = 0; i < 10; i++) { x += '<option value=' + (i + 48) + '>' + i + '</option>'; }
1310
+ for (var i = 0; i < 26; i++) { x += '<option value=' + (i + 65) + '>' + String.fromCharCode(i + 65) + '</option>'; }
1311
+ x += '</select> <input type=button value=' + "Add" + ' onclick=addDeskCustomizeKey() /></div>';
1312
+ QH('p10dialog2', x);
1313
+ xxdialogMode = 2;
1314
+ QV('p10dialog', true);
1315
+ deskUpdateShortcutList();
1316
+ }
1317
956
- // Check if we are in single desktop mode
957
- if (cv.id == 'Desk') { deskAdjust(); return; }
1318
+ function deskCustomizeKeysEx() {
1319
+ QV('p10dialog', false);
1320
+ xxdialogMode = 0;
1321
+ putstore('deskKeyShortcuts', deskKeyboardShortcuts.join(','));
1322
+ updateDeskShortcutKeys();
1323
+ }
1324
959
- // Figure out and adjust the size to fill the width of the div
960
- var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
961
- var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
962
- xw = realw + Math.floor((tw - (xw * realw)) / xw);
963
- vsize.y = vsize.y * (xw / vsize.x);
964
- vsize.x = xw;
965
- var mh = vsize.y, mw = vsize.x;
966
- if (mod.State != 0) { mh = vsize.y; mw = (sw / sh) * vsize.y; }
967
- QS(cv.id)['max-height'] = mh + 'px';
968
- QS(cv.id)['max-width'] = mw + 'px';
969
- QS(cv.id)['margin-top'] = '0';
970
- QS(cv.id)['margin-bottom'] = '0';
1325
+ function deskUpdateShortcutList() {
1326
+ var x = '';
1327
+ for (var i in deskKeyboardShortcuts) {
1328
+ var kt = keyShortcutTotext(deskKeyboardShortcuts[i]), orderButtons = '';
1329
+ if (i != (deskKeyboardShortcuts.length - 1)) { orderButtons += '<img width=8 height=8 style=float:right;cursor:pointer;padding:3px src="images/c2.png" onclick=deskCustomizeKeyDown(' + deskKeyboardShortcuts[i] + ')>'; }
1330
+ if (i != 0) { orderButtons += '<img width=8 height=8 style=float:right;cursor:pointer;padding:3px src="images/c3.png" onclick=deskCustomizeKeyUp(' + deskKeyboardShortcuts[i] + ')>'; }
1331
+ x += '<div style="width:100%;background-color:#AAA;border-radius:4px;margin-bottom:4px;padding:4px;text-align:left;box-sizing:border-box" value=' + deskKeyboardShortcuts[i] + '>' + kt + '<img width=10 height=10 style=float:right;cursor:pointer;padding:2px;margin-left:8px src="images/trash.png" onclick=removeDeskCustomizeKey(' + deskKeyboardShortcuts[i] + ')>' + orderButtons + '</div>';
1332
+ }
1333
+ if (x == '') { x = '<i>' + "No keyboard shortcuts defined" + '</i>'; }
1334
+ QH('d2shortcuts', x);
1335
}
1336
973
- // Remote desktop special key combos for Windows
974
- function deskSendKeys() {
975
- if (xxdialogMode || desktop == null || desktop.State != 3) return;
976
- var ks = Q('deskkeys').value;
977
- if (ks == 0) { // WIN+Down arrow
978
- if (desktop.contype == 2) {
979
- desktop.m.sendkey([[0xffe7, 1], [0xff54, 1], [0xff54, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Down arrow press, Down arrow release, Meta-left release
980
- } else {
981
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 40], [desktop.m.KeyAction.UP, 40], [desktop.m.KeyAction.EXUP, 0x5B]]); // Agent: L-Winkey press, Down arrow press, Down arrow release, L-Winkey release
982
- }
983
- } else if (ks == 1) { // WIN+Up arrow
984
- if (desktop.contype == 2) {
985
- desktop.m.sendkey([[0xffe7, 1], [0xff52, 1], [0xff52, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Up arrow press, Up arrow release, Meta-left release
986
- } else {
987
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 38], [desktop.m.KeyAction.UP, 38], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, Up arrow press, Up arrow release, L-Winkey release
988
- }
989
- } else if (ks == 2) { // WIN+L arrow
990
- if (desktop.contype == 2) {
991
- desktop.m.sendkey([[0xffe7, 1], [0x6c, 1], [0x6c, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'l' press, 'l' release, Meta-left release
992
- } else {
993
- desktop.sendCtrlMsg('{"action":"lock"}');
994
- //desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN,0x5B],[desktop.m.KeyAction.DOWN,76],[desktop.m.KeyAction.UP,76],[desktop.m.KeyAction.EXUP,0x5B]]); // MeshAgent: L-Winkey press, 'L' press, 'L' release, L-Winkey release
995
- //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXDOWN, 0x5B);
996
- //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.DOWN, 76);
997
- //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.UP, 76);
998
- //desktop.m.SendKeyMsgKC(desktop.m.KeyAction.EXUP, 0x5B);
999
- }
1000
- } else if (ks == 3) { // WIN+M arrow
1001
- if (desktop.contype == 2) {
1002
- desktop.m.sendkey([[0xffe7, 1], [0x6d, 1], [0x6d, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'm' press, 'm' release, Meta-left release
1003
- } else {
1004
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 77], [desktop.m.KeyAction.UP, 77], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, 'M' press, 'M' release, L-Winkey release
1005
- }
1006
- } else if (ks == 4) { // Shift+WIN+M arrow
1007
- if (desktop.contype == 2) {
1008
- desktop.m.sendkey([[0xffe1, 1], [0xffe7, 1], [0x6d, 1], [0x6d, 0], [0xffe7, 0], [0xffe1, 0]]); // Intel AMT: Shift-left down, Meta-left down, 'm' press, 'm' release, Meta-left release, Shift-left release
1009
- } else {
1010
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.DOWN, 16], [desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 77], [desktop.m.KeyAction.UP, 77], [desktop.m.KeyAction.EXUP, 0x5B], [desktop.m.KeyAction.UP, 16]]); // MeshAgent: L-shift press, L-Winkey press, 'M' press, 'M' release, L-Winkey release, L-shift release
1011
- }
1012
- } else if (ks == 5) { // WIN
1013
- if (desktop.contype == 2) {
1014
- desktop.m.sendkey([[0xffe7, 1], [0xffe7, 0]]); // Intel AMT: Meta-left down, Meta-left release
1015
- } else {
1016
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, L-Winkey release
1017
- }
1018
- } else if (ks == 6) { // WIN+R
1019
- if (desktop.contype == 2) {
1020
- desktop.m.sendkey([[0xffe7, 1], [0x72, 1], [0x72, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, 'r' press, 'r' release, Meta-left release
1021
- } else {
1022
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 82], [desktop.m.KeyAction.UP, 82], [desktop.m.KeyAction.EXUP, 0x5B]]); // MeshAgent: L-Winkey press, 'R' press, 'R' release, L-Winkey release
1023
- }
1024
- } else if (ks == 7) { // ALT-F4
1025
- if (desktop.contype == 2) {
1026
- desktop.m.sendkey([[0xffe9, 1], [0xffc1, 1], [0xffc1, 0], [0xffe9, 0]]); // Intel AMT: Alt down, 'F4' press, 'F4' release, Alt release
1027
- } else {
1028
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 18], [desktop.m.KeyAction.DOWN, 115], [desktop.m.KeyAction.UP, 115], [desktop.m.KeyAction.EXUP, 18]]); // MeshAgent: Alt press, 'F4' press, 'F4' release, Alt release
1029
- }
1030
- } else if (ks == 8) { // CTRL-W
1031
- if (desktop.contype == 2) {
1032
- desktop.m.sendkey([[0xffe3, 1], [0x77, 1], [0x77, 0], [0xffe3, 0]]); // Intel AMT: Ctrl down, 'w' press, 'w' release, Ctrl release
1033
- } else {
1034
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 17], [desktop.m.KeyAction.DOWN, 87], [desktop.m.KeyAction.UP, 87], [desktop.m.KeyAction.EXUP, 17]]); // MeshAgent: Ctrl press, 'W' press, 'W' release, Ctrl release
1035
- }
1036
- } else if (ks == 9) { // ALT-TAB
1037
- if (desktop.contype == 2) {
1038
- desktop.m.sendkey([[0xffe9, 1], [0xff09, 1], [0xff09, 0], [0xffe9, 0]]); // Intel AMT: Alt down, 'TAB' press, 'TAB' release, Alt release
1039
- } else {
1040
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 18], [desktop.m.KeyAction.DOWN, 9], [desktop.m.KeyAction.UP, 9], [desktop.m.KeyAction.EXUP, 18]]); // MeshAgent: Alt press, 'TAB' press, 'TAB' release, Alt release
1041
- }
1042
- } else if (ks == 10) { // CTRL-ALT-DEL
1043
- desktop.m.sendcad();
1044
- } else if (ks == 11) { // WIN-LEFT
1045
- if (desktop.contype == 2) {
1046
- desktop.m.sendkey([[0xffe7, 1], [0xff51, 1], [0xff51, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Left arrow press, Left arrow release, Meta-left release
1047
- } else {
1048
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 37], [desktop.m.KeyAction.UP, 37], [desktop.m.KeyAction.EXUP, 0x5B]]);
1049
- }
1050
- } else if (ks == 12) { // WIN-RIGHT
1051
- if (desktop.contype == 2) {
1052
- desktop.m.sendkey([[0xffe7, 1], [0xff53, 1], [0xff53, 0], [0xffe7, 0]]); // Intel AMT: Meta-left down, Right arrow press, Right arrow release, Meta-left release
1053
- } else {
1054
- desktop.m.SendKeyMsgKC([[desktop.m.KeyAction.EXDOWN, 0x5B], [desktop.m.KeyAction.DOWN, 39], [desktop.m.KeyAction.UP, 39], [desktop.m.KeyAction.EXUP, 0x5B]]);
1055
- }
1056
- }
1057
- }
1058
-
1059
-
1060
- var gotKeyPressEvent = false;
1061
- function ondeskkeypress(e, t) {
1062
- setSessionActivity();
1063
- if (desktop && !xxdialogMode && (xxcurrentView == 11)) {
1064
- gotKeyPressEvent = true;
1065
- Q('softKeyboard').value = '';
1066
- // Check what keys we are allows to send
1067
- var inputAllowed = true; // TODO
1068
- if (inputAllowed == false) return false;
1069
- return desktop.m.handleKeys(e);
1070
- }
1071
- if (terminal && !xxdialogMode && (xxcurrentView == 12) (t !== 1)) {
1072
- if (e.altKey == true) { return true; }
1073
- gotKeyPressEvent = true;
1074
- Q('softKeyboard').value = '';
1075
- var k = 0;
1076
- if (e.charCode != 0) { k = e.charCode; } else if (e.keyCode != 0) { k = e.keyCode; }
1077
- if (k != 0) {
1078
- if (terminal.urlname == 'sshterminalrelay.ashx') {
1079
- // SSH
1080
- terminal.socket.send('~' + String.fromCharCode(k));
1081
- } else {
1082
- // Agent
1083
- terminal.sendText(String.fromCharCode(k));
1084
- }
1085
- }
1086
- return false;
1087
- }
1088
- }
1089
-
1090
- function ondeskkeydown(e, t) {
1091
- setSessionActivity();
1092
- if (desktop && !xxdialogMode && (xxcurrentView == 11)) {
1093
- gotKeyPressEvent = false;
1094
- Q('softKeyboard').value = '';
1095
- // Check what keys we are allows to send
1096
- var inputAllowed = true; // TODO
1097
- if (inputAllowed == false) return false;
1098
- return desktop.m.handleKeyDown(e);
1099
- }
1100
- if (terminal && !xxdialogMode && (xxcurrentView == 12) && (t !== 1)) {
1101
- if (e.altKey == true) { return true; }
1102
- Q('softKeyboard').value = '';
1103
- gotKeyPressEvent = false;
1104
- var k = 0;
1105
- if (e.charCode != 0) { k = e.charCode; } else if (e.keyCode != 0) { k = e.keyCode; }
1106
- if (k == 8) { terminal.sendText(String.fromCharCode(k)); } // Enter and backspace
1107
- else if (e.ctrlKey && (k >= 64) && (k <= 95)) {
1108
- // Ctrl keys
1109
- if (terminal.urlname == 'sshterminalrelay.ashx') {
1110
- // SSH
1111
- terminal.socket.send('~' + String.fromCharCode(k - 64));
1112
- } else {
1113
- // Agent
1114
- terminal.sendText(String.fromCharCode(k - 64));
1115
- }
1116
- }
1117
- }
1118
- }
1119
-
1120
- function ondeskkeyup(e, t) {
1121
- setSessionActivity();
1122
- if (desktop && !xxdialogMode && (xxcurrentView == 11)) {
1123
- var inputStr = Q('softKeyboard').value;
1124
- Q('softKeyboard').value = '';
1125
- // Check what keys we are allows to send
1126
- var inputAllowed = true; // TODO
1127
- if (inputAllowed == false) return false;
1128
- if ((gotKeyPressEvent == false) && (inputStr.length > 0) && desktop.m.SendKeyUnicode) {
1129
- // This is a mobile keyboard, we need to send that is in the input control.
1130
- var inputchar = inputStr[inputStr.length - 1].charCodeAt(0);
1131
- desktop.m.SendKeyUnicode(desktop.m.KeyAction.DOWN, inputchar);
1132
- desktop.m.SendKeyUnicode(desktop.m.KeyAction.UP, inputchar);
1133
- } else {
1134
- return desktop.m.handleKeyUp(e);
1135
- }
1136
- }
1137
- if (terminal && !xxdialogMode && (xxcurrentView == 12) && (gotKeyPressEvent == false) && (t !== 1)) {
1138
- if (e.altKey == true) { return true; }
1139
- var inputStr = Q('softKeyboard').value;
1140
- Q('softKeyboard').value = '';
1141
- if (terminal.urlname == 'sshterminalrelay.ashx') {
1142
- // SSH
1143
- terminal.socket.send('~' + inputStr);
1144
- } else {
1145
- // Agent
1146
- if (inputStr) terminal.sendText(inputStr);
1147
- }
1148
- return false;
1149
- }
1150
- }
1151
-
1152
-
1153
- // Remote desktop typing
1154
- function showDeskType() {
1155
- if (xxdialogMode || desktop == null || desktop.State != 3) return;
1156
- Q('DeskType').blur();
1157
- var x = '<div>' + "Enter text and click OK to remotely type it using a US english keyboard. Make sure to place the remote cursor at the correct position before proceeding." + '<div>';
1158
- x += '<textarea id=d2typeText style="margin-top:5px;width:100%;height:184px;resize:none" maxlength=2000></textarea>';
1159
- setDialogMode(2, "Remote Keyboard Entry", 3, showDeskTypeEx, x);
1160
- Q('d2typeText').focus();
1161
- }
1162
-
1163
- var AmtDeskTypeTimer = null;
1164
- var AmtDeskTypeContent = null;
1165
- var DeskTypeTranslate = { 39: 222, 42: 106, 43: 107, 44: 188, 45: 189, 46: 190, 47: 191, 59: 186, 61: 187, 91: 219, 92: 220, 93: 221, 96: 192, 191: 111 };
1166
- var DeskTypeShiftTranslate = { 33: 49, 34: 222, 35: 51, 36: 52, 37: 53, 38: 55, 40: 57, 41: 48, 58: 186, 60: 188, 62: 190, 63: 191, 64: 50, 94: 54, 95: 189, 106: 56, 107: 187, 123: 219, 124: 220, 125: 221, 126: 192 };
1167
- function showDeskTypeEx() {
1168
- var txt = Q('d2typeText').value, ltxt = Q('d2typeText').value.toUpperCase(), x = [], shift = false;
1169
- if (desktop.contype == 2) {
1170
- // Intel AMT
1171
- for (var i in txt) { var a = txt.charCodeAt(i); x.push([a, 1], [a, 0]); }
1172
- AmtDeskTypeContent = x;
1173
- AmtDeskTypeTimer = setInterval(function () {
1174
- var key = AmtDeskTypeContent.shift();
1175
- if (desktop) { desktop.m.sendkey(key[0], key[1]); }
1176
- if ((desktop == null) || (AmtDeskTypeContent.length == 0)) { clearInterval(AmtDeskTypeTimer); AmtDeskTypeContent = null; }
1177
- }, 10);
1178
- } else {
1179
- // MeshAgent
1180
- for (var i in txt) {
1181
- var a = txt.charCodeAt(i), b = ltxt.charCodeAt(i);
1182
- if (((a >= 65) && (a <= 90)) || ((a >= 97) && (a <= 122))) {
1183
- if ((a == b) && (shift == false)) { x.push([desktop.m.KeyAction.DOWN, 16]); shift = true; } // LShift down
1184
- if ((a != b) && (shift == true)) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // LShift up
1185
- } else if ((a >= 48) && (a <= 57)) {
1186
- if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
1187
- } else if (DeskTypeTranslate[a]) {
1188
- if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
1189
- b = DeskTypeTranslate[a];
1190
- } else if (DeskTypeShiftTranslate[a]) {
1191
- if (shift == false) { x.push([desktop.m.KeyAction.DOWN, 16]); shift = true; } // LShift down
1192
- b = DeskTypeShiftTranslate[a];
1193
- }
1194
- x.push([desktop.m.KeyAction.DOWN, b], [desktop.m.KeyAction.UP, b]);
1195
- }
1196
- if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
1197
- desktop.m.SendKeyMsgKC(x);
1198
- }
1337
+ function deskCustomizeKeyDown(k) {
1338
+ var i = deskKeyboardShortcuts.indexOf(k), x = deskKeyboardShortcuts[i + 1];
1339
+ deskKeyboardShortcuts[i + 1] = deskKeyboardShortcuts[i];
1340
+ deskKeyboardShortcuts[i] = x;
1341
+ deskUpdateShortcutList();
1342
}
1343
1201
- /*
1202
- // Show clipboard dialog
1203
- function showDeskClip() {
1204
- if (xxdialogMode || desktop == null || desktop.State != 3) return;
1205
- Q('DeskClip').blur();
1206
- var x = '';
1207
- x += '<input id=dlgClipGet type=button value="Get Clipboard" style=width:120px onclick=showDeskClipGet()>';
1208
- x += '<input id=dlgClipSet type=button value="Set Clipboard" style=width:120px onclick=showDeskClipSet()>';
1209
- x += '<div id=dlgClipStatus style="display:inline-block;margin-left:8px" ></div>';
1210
- x += '<textarea id=d2clipText style="width:100%;height:184px;resize:none" maxlength=65535></textarea>';
1211
- x += '<input type=button value="Close" style=width:80px;float:right onclick=dialogclose(0)><div style=height:26px;margin-top:3px><span id=linuxClipWarn style=display:none>' + "Remote clipboard is valid for 60 seconds." + '</span> </div><div></div>';
1212
- setDialogMode(2, "Remote Clipboard", 8, null, x, 'clipboard');
1213
- Q('d2clipText').focus();
1344
+ function deskCustomizeKeyUp(k) {
1345
+ var i = deskKeyboardShortcuts.indexOf(k), x = deskKeyboardShortcuts[i];
1346
+ deskKeyboardShortcuts[i] = deskKeyboardShortcuts[i - 1];
1347
+ deskKeyboardShortcuts[i - 1] = x;
1348
+ deskUpdateShortcutList();
1349
}
1350
1216
- function showDeskClipGet() {
1217
- if (desktop == null || desktop.State != 3) return;
1218
- meshserver.send({ action: 'msg', type: 'getclip', nodeid: currentNode._id });
1351
+ function removeDeskCustomizeKey(k) {
1352
+ var na = [];
1353
+ for (var i in deskKeyboardShortcuts) { if (deskKeyboardShortcuts[i] != k) { na.push(deskKeyboardShortcuts[i]); } }
1354
+ deskKeyboardShortcuts = na;
1355
+ deskUpdateShortcutList();
1356
}
1357
1221
- function showDeskClipSet() {
1222
- if (desktop == null || desktop.State != 3) return;
1223
- meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: Q('d2clipText').value });
1224
- //QV('linuxClipWarn', currentNode && currentNode.agent && (currentNode.agent.id > 4) && (currentNode.agent.id != 21) && (currentNode.agent.id != 22));
1358
+ function addDeskCustomizeKey() {
1359
+ var k = parseInt(Q('d2keySelect').value);
1360
+ if (Q('d1kshift').checked) { k |= 0x010000; }
1361
+ if (Q('d1kalt').checked) { k |= 0x020000; }
1362
+ if (Q('d1kctrl').checked) { k |= 0x080000; }
1363
+ if (Q('d1kwin').checked) { k |= 0x100000; }
1364
+ if ((k > 0) && (deskKeyboardShortcuts.indexOf(k) == -1)) { deskKeyboardShortcuts.push(k); deskUpdateShortcutList(); }
1365
}
1226
- */
1366
1228
- // Send CTRL-ALT-DEL
1229
- function sendCAD() {
1367
+ // Remote desktop special key combos for Windows
1368
+ function deskSendKeys(ks) {
1369
if (xxdialogMode || desktop == null || desktop.State != 3) return;
1231
- desktop.m.sendcad();
1232
- }
1370
1234
- // Toggle mouse and keyboard input
1235
- function toggleKvmControl() { QS('DeskControlSpan').color = Q('DeskControl').checked ? null : 'red'; }
1236
-
1237
- // Save the desktop image to file
1238
- function deskSaveImage() {
1239
- if (xxdialogMode || desktop == null || desktop.State != 3) return;
1240
- var d = new Date(), n = "Desktop" + '-' + d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + '-' + ('0' + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);
1241
- Q('Desk')['toBlob'](function (blob) { saveAs(blob, n + '.png'); });
1242
- }
1371
+ // Construct the key command
1372
+ if (ks == -1) { deskCustomizeKeys(); return; } // Customize
1373
+ if (ks == 0x0A002E) { desktop.m.sendcad(); return; } // CTRL-ALT-DEL
1374
+ //if ((desktop.contype == 1) && (ks == 0x10004C)) { desktop.sendCtrlMsg('{"action":"lock"}'); return; } // Lock desktop, WIN + L
1375
1244
- function deskDisplayInfo(sender, displays, selDisplay) {
1245
- var displayCount = 0, displaySelector = '';
1246
- for (var i in displays) {
1247
- displayCount++;
1248
- displaySelector += '<option' + ((selDisplay == i) ? ' selected' : '') + ' value=' + i + '>' + displays[i] + '</option>';
1249
- if ((deskPreferedStickyDisplay == i) && (selDisplay != deskPreferedStickyDisplay)) { desktop.m.SetDisplay(i); }
1250
- deskPreferedStickyDisplay = -1;
1376
+ var flags = (ks & 0xFF0000) >> 16, key = (ks & 0xFFFF), keyArray = [], keyArray2 = [];
1377
+ var amtTranslate = {
1378
+ 8: 0xff08, // BackSpace
1379
+ 9: 0xff09, // Tab
1380
+ 13: 0xff0d, // Return or Enter
1381
+ 27: 0xff1b, // Escape
1382
+ 45: 0xff63, // Insert
1383
+ 46: 0xffff, // Delete
1384
+ 36: 0xff50, // Home
1385
+ 35: 0xff57, // End
1386
+ 33: 0xff55, // Page Up
1387
+ 34: 0xff56, // Page Down
1388
+ 37: 0xff51, // Left arrow
1389
+ 38: 0xff52, // Up arrow
1390
+ 39: 0xff53, // Right arrow
1391
+ 40: 0xff54, // Down arrow
1392
+ 112: 0xffbe, // F1
1393
+ 113: 0xffbf, // F2
1394
+ 114: 0xffc0, // F3
1395
+ 115: 0xffc1, // F4
1396
+ 116: 0xffc2, // F5
1397
+ 117: 0xffc3, // F6
1398
+ 118: 0xffc4, // F7
1399
+ 119: 0xffc5, // F8
1400
+ 120: 0xffc6, // F9
1401
+ 121: 0xffc7, // F10
1402
+ 122: 0xffc8, // F11
1403
+ 123: 0xffc9 // F12
1404
}
1252
- QH('termdisplays', displaySelector);
1253
- QV('termdisplays', displayCount > 1);
1254
- }
1405
1256
- function deskGetDisplayNumbers(e) { desktop.m.GetDisplayNumbers(); }
1257
- var deskPreferedStickyDisplay = -1;
1258
- function deskSetDisplay(e) { desktop.m.SetDisplay(deskPreferedStickyDisplay = parseInt(Q('termdisplays').value)); Q('termdisplays').blur(); }
1406
+ // 0x010000 = Shift
1407
+ // 0x020000 = Left-Alt
1408
+ // 0x080000 = Ctrl
1409
+ // 0x100000 = Window
1410
1260
- // Double click detection. This is important for macOS.
1261
- var dblClickDetectArgs = { t: 0, x: 0, y: 0 };
1262
- function dblClickDetect(e) {
1263
- if (e.buttons != 1) return;
1264
- var t = Date.now();
1265
- if (((t - dblClickDetectArgs.t) < 250) && (Math.abs(e.clientX - dblClickDetectArgs.x) < 2) && (Math.abs(e.clientY - dblClickDetectArgs.y) < 2)) {
1266
- if (!xxdialogMode && desktop != null && isInputAllowed()) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousedblclick(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousedblclick(e); } }
1411
+ if (desktop.contype == 2) {
1412
+ // Intel AMT
1413
+ if (flags & 1) { keyArray.push([0xffe1, 1]); keyArray2.push([0xffe1, 0]); } // Shift
1414
+ if (flags & 2) { keyArray.push([0xffe9, 1]); keyArray2.push([0xffe9, 0]); } // Left-alt
1415
+ if (flags & 8) { keyArray.push([0xffe3, 1]); keyArray2.push([0xffe3, 0]); } // Ctrl
1416
+ if (flags & 16) { keyArray.push([0xffe7, 1]); keyArray2.push([0xffe7, 0]); } // Windows key
1417
+ if (amtTranslate[key]) { key = amtTranslate[key]; }
1418
+ if ((key >= 65) && (key <= 90)) { key += 32; }
1419
+ if (key != 0) { keyArray.push([key, 1]); keyArray2.push([key, 0]); }
1420
+ keyArray2.reverse();
1421
+ for (var i = 0; i < keyArray2.length; i++) { keyArray.push(keyArray2[i]); }
1422
+ desktop.m.sendkey(keyArray);
1423
+ } else {
1424
+ // Agent desktop
1425
+ if (flags & 1) { keyArray.push([desktop.m.KeyAction.DOWN, 16]); keyArray2.push([desktop.m.KeyAction.UP, 16]); } // Shift
1426
+ if (flags & 2) { keyArray.push([desktop.m.KeyAction.EXDOWN, 18]); keyArray2.push([desktop.m.KeyAction.EXUP, 18]); } // Left-alt
1427
+ if (flags & 8) { keyArray.push([desktop.m.KeyAction.EXDOWN, 17]); keyArray2.push([desktop.m.KeyAction.EXUP, 17]); } // Ctrl
1428
+ if (flags & 16) { keyArray.push([desktop.m.KeyAction.EXDOWN, 0x5B]); keyArray2.push([desktop.m.KeyAction.EXUP, 0x5B]); } // Windows key
1429
+ if (key != 0) { keyArray.push([desktop.m.KeyAction.DOWN, key]); keyArray2.push([desktop.m.KeyAction.UP, key]); }
1430
+ keyArray2.reverse();
1431
+ for (var i = 0; i < keyArray2.length; i++) { keyArray.push(keyArray2[i]); }
1432
+ desktop.m.SendKeyMsgKC(keyArray);
1433
}
1268
- dblClickDetectArgs.t = t;
1269
- dblClickDetectArgs.x = e.clientX;
1270
- dblClickDetectArgs.y = e.clientY;
1434
}
1435
1273
- function dmousedown(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) { if (fullscreen) { e.addx = Q('deskarea0').scrollLeft * (1 / fullscreenzoom); e.addy = Q('deskarea0').scrollTop * (1 / fullscreenzoom); } desktop.m.mousedown(e); } }
1274
- function dmouseup(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) { if (fullscreen) { e.addx = Q('deskarea0').scrollLeft * (1 / fullscreenzoom); e.addy = Q('deskarea0').scrollTop * (1 / fullscreenzoom); } desktop.m.mouseup(e); } }
1275
- function dmousemove(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) { if (fullscreen) { e.addx = Q('deskarea0').scrollLeft * (1 / fullscreenzoom); e.addy = Q('deskarea0').scrollTop * (1 / fullscreenzoom); } desktop.m.mousemove(e); } }
1276
- function dmousewheel(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null) && desktop.m.mousewheel) { if (fullscreen) { e.addx = Q('deskarea0').scrollLeft * (1 / fullscreenzoom); e.addy = Q('deskarea0').scrollTop * (1 / fullscreenzoom); } desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
1277
-
1278
- var keyboardShown = false;
1279
- var keyboardShownTimer = null;
1280
- var fullScreenMode = false;
1281
- function toggleKeyboard() {
1436
+ function toggleMenu(x) {
1437
if (xxdialogMode) return;
1283
- if (keyboardShownTimer != null) { clearTimeout(keyboardShownTimer); }
1284
- if (keyboardShown) { Q('softKeyboard').blur(); keyboardShown = false; } else { Q('softKeyboard').focus(); keyboardShown = true; }
1285
- QV('deskkeybutton2a', fullscreen && !keyboardShown);
1286
- QV('deskkeybutton2b', fullscreen && keyboardShown);
1438
+ QV('deskButtonMenu', fullscreen && !x && (currentDevicePanel == 1));
1439
+ QV('termButtonMenu', fullscreen && !x && (currentDevicePanel == 5));
1440
+ QV('deskkeybutton3a', fullscreen && x);
1441
+ QV('deskkeybutton3b', fullscreen && !x);
1442
}
1443
1289
- function keyboardFocusChange() {
1290
- keyboardShownTimer = setTimeout(function () {
1291
- keyboardShownTimer = null;
1292
- keyboardShown = (Q('softKeyboard') == document.activeElement);
1293
- QV('deskkeybutton2a', fullscreen && !keyboardShown);
1294
- QV('deskkeybutton2b', fullscreen && keyboardShown);
1295
- }, 100);
1444
+ function deskChangeMouseButton(x) {
1445
+ if (xxdialogMode) return;
1446
+ if (desktop == null) return;
1447
+ desktop.m.SwapMouse = !desktop.m.SwapMouse;
1448
+ QV('deskkeybutton4a', fullscreen && (!desktop.m.SwapMouse));
1449
+ QV('deskkeybutton4b', fullscreen && (desktop.m.SwapMouse));
1450
}
1451
1298
- function exitButton() {
1452
+ function deskChangeFullscreenZoom() {
1453
if (xxdialogMode) return;
1300
- QV('deskButtonMenu', false);
1301
- QV('termButtonMenu', false);
1302
- if (fullscreenzoom == 1) {
1303
- deskToggleFull();
1304
- } else {
1305
- deskChangeFullscreenZoom();
1306
- setTimeout(deskToggleFull, 10);
1454
+ if (currentDevicePanel == 1) {
1455
+ if (desktop == null) return;
1456
+ if (fullscreenzoom == 1) { fullscreenzoom = 0.5; } else { fullscreenzoom = 1; }
1457
+ QV('deskkeybutton5a', fullscreen && (fullscreenzoom == 1));
1458
+ QV('deskkeybutton5b', fullscreen && (fullscreenzoom != 1));
1459
+ QS('deskarea3').width = (desktop.m.ScreenWidth * fullscreenzoom) + 'px';
1460
+ QS('deskarea3').height = (desktop.m.ScreenHeight * fullscreenzoom) + 'px';
1461
+ deskAdjust();
1462
+ }
1463
+ if (currentDevicePanel == 5) {
1464
+ if (terminal == null) return;
1465
+ xterm.setOption('fontSize', (xterm.getOption('fontSize') == 15) ? 10 : 15)
1466
}
1467
}
1468
1310
- function deskMenuButton(x) {
1311
- toggleMenu(true);
1312
- deskSendKeys(x);
1313
- }
1314
-
1315
-
1316
- //
1317
- // Desktop Shortcut Keys
1318
- //
1319
-
1320
- function updateDeskShortcutKeys() {
1321
- var x = ''; //'<div class="menuButton" onclick="deskMenuButton(-1)">' + "Customize" + '</div>';
1322
- for (var i in deskKeyboardShortcuts) { x += '<div class="menuButton" onclick="deskMenuButton(' + deskKeyboardShortcuts[i] + ')">' + keyShortcutTotext(deskKeyboardShortcuts[i]) + '</div>'; }
1323
- QH('deskButtonMenu', x);
1324
- }
1325
-
1326
- var keyStrings = { 8: "BackSpace", 9: "Tab", 13: "Enter", 27: "Escape", 44: "Print Screen", 45: "Insert", 46: "Del", 36: "Home", 35: "End", 33: "Page Up", 34: "Page Down", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 0: "None" }
1327
-
1328
- function keyShortcutTotext(n) {
1329
- var x = [];
1330
- if (n & 0x010000) { x.push("Shift"); }
1331
- if (n & 0x020000) { x.push("Alt"); }
1332
- if (n & 0x080000) { x.push("Ctrl"); }
1333
- if (n & 0x100000) { x.push("Win"); }
1334
- n = (n & 0xFFFF);
1335
- if ((n >= 112) && (n <= 123)) { x.push('F' + (n - 111)); } // Fx keys
1336
- else if ((n != 0) && (keyStrings[n])) { x.push(keyStrings[n]); }
1337
- else { if (n != 0) { x.push(String.fromCharCode(n)); } }
1338
- return x.join(' + ');
1339
- }
1340
-
1341
- // Customize keyboard shortcuts
1342
- function deskCustomizeKeys() {
1343
- if (xxdialogMode) return;
1344
- var x = '<div id=d2shortcuts style="width:100%;height:180px;padding:4px;overflow-y:auto;border:1px solid gray"></div><div style=width:100%;padding:5px>';
1345
- x += '<label><input id=d1kshift type=checkbox /> ' + "Shift" + '</label><label> <input id=d1kalt type=checkbox /> ' + "Alt" + '</label><label> <input id=d1kctrl type=checkbox /> ' + "Ctrl" + '</label> <input id=d1kwin type=checkbox /> ' + "Win" + '</label>';
1346
- x += ' <select id=d2keySelect>';
1347
- for (var i in keyStrings) { x += '<option value=' + i + '>' + keyStrings[i] + '</option>'; }
1348
- for (var i = 1; i <= 12; i++) { x += '<option value=' + (i + 111) + '>F' + i + '</option>'; }
1349
- for (var i = 0; i < 10; i++) { x += '<option value=' + (i + 48) + '>' + i + '</option>'; }
1350
- for (var i = 0; i < 26; i++) { x += '<option value=' + (i + 65) + '>' + String.fromCharCode(i + 65) + '</option>'; }
1351
- x += '</select> <input type=button value=' + "Add" + ' onclick=addDeskCustomizeKey() /></div>';
1352
- QH('p10dialog2', x);
1353
- xxdialogMode = 2;
1354
- QV('p10dialog', true);
1355
- deskUpdateShortcutList();
1356
- }
1469
+ var fullscreen = false;
1470
+ var fullscreenzoom = 1;
1471
+ function deskToggleFull() {
1472
+ fullscreen = !fullscreen;
1473
+ QV('mastheadx', !fullscreen);
1474
+ QV('masthead', !fullscreen);
1475
+ QV('topbar', !fullscreen);
1476
+ QV('p11deviceNameHeader', !fullscreen);
1477
+ QV('footer', !fullscreen);
1478
+ QV('column_l_bottomgap', !fullscreen);
1479
+ QV('idx_deskFullBtn2', fullscreen);
1480
+ QV('deskFullBtn', !fullscreen);
1481
+ QV('p10deskTopTable', !fullscreen);
1482
+ QV('deskarea1', !fullscreen);
1483
+ QV('deskarea4', !fullscreen);
1484
+ QV('termarea1', !fullscreen);
1485
+ QV('termarea4', !fullscreen);
1486
+
1487
+ var rights = GetNodeRights(currentNode);
1488
+ var inputAllowed = ((features2 & 0x2000) == 0) && (currentNode.agent.id != 14) && ((rights == 0xFFFFFFFF) || (((rights & 8) != 0) && ((rights & 256) == 0) && ((rights & 4096) == 0)));
1489
1358
- function deskCustomizeKeysEx() {
1359
- QV('p10dialog', false);
1360
- xxdialogMode = 0;
1361
- //putstore('deskKeyShortcuts', deskKeyboardShortcuts.join(','));
1362
- updateDeskShortcutKeys();
1363
- }
1490
+ // Show full screen buttons if needed
1491
+ QV('deskkeybutton1', fullscreen);
1492
+ if (currentDevicePanel == 1) { // Desktop panel is being shown (1 = Desktop, 5 = Terminal)
1493
+ // Move shortcut key to desktop position
1494
+ QS('deskkeybutton2a').top = QS('deskkeybutton2b').top = '210px';
1495
+ // Move the zoom button to normal or top position
1496
+ QS('deskkeybutton5a').top = QS('deskkeybutton5b').top = (inputAllowed) ? '160px' : '60px'; // Zoom
1497
+ QV('deskkeybutton2a', fullscreen && inputAllowed);
1498
+ QV('deskkeybutton2b', false);
1499
+ QV('deskkeybutton3a', fullscreen && inputAllowed);
1500
+ QV('deskkeybutton3b', false);
1501
+ QV('deskkeybutton4a', fullscreen && inputAllowed && (!desktop.m.SwapMouse));
1502
+ QV('deskkeybutton4b', fullscreen && inputAllowed && (desktop.m.SwapMouse));
1503
+ QV('deskkeybutton5a', fullscreen && (fullscreenzoom == 1));
1504
+ QV('deskkeybutton5b', fullscreen && (fullscreenzoom != 1));
1505
+ }
1506
+ if (currentDevicePanel == 5) {
1507
+ // Move right buttons to terminal position
1508
+ //QS('deskkeybutton3a').top = QS('deskkeybutton3b').top = '60px'; // Shortcuts
1509
+ //QS('deskkeybutton5a').top = QS('deskkeybutton5b').top = '110px'; // Zoom
1510
+ QS('deskkeybutton2a').top = QS('deskkeybutton2b').top = '110px'; // Keyboard
1511
+ QV('deskkeybutton2a', fullscreen);
1512
+ QV('deskkeybutton2b', false);
1513
+ QV('deskkeybutton3a', fullscreen);
1514
+ QV('deskkeybutton3b', false);
1515
+ QV('deskkeybutton4a', false);
1516
+ QV('deskkeybutton4b', false);
1517
+ QV('deskkeybutton5a', false);
1518
+ QV('deskkeybutton5a', false);
1519
+ //QV('deskkeybutton5a', xterm.getOption('fontSize') == 15);
1520
+ //QV('deskkeybutton5b', xterm.getOption('fontSize') != 15);
1521
+ }
1522
1365
- function deskUpdateShortcutList() {
1366
- var x = '';
1367
- for (var i in deskKeyboardShortcuts) {
1368
- var kt = keyShortcutTotext(deskKeyboardShortcuts[i]), orderButtons = '';
1369
- if (i != (deskKeyboardShortcuts.length - 1)) { orderButtons += '<img width=8 height=8 style=float:right;cursor:pointer;padding:3px src="images/c2.png" onclick=deskCustomizeKeyDown(' + deskKeyboardShortcuts[i] + ')>'; }
1370
- if (i != 0) { orderButtons += '<img width=8 height=8 style=float:right;cursor:pointer;padding:3px src="images/c3.png" onclick=deskCustomizeKeyUp(' + deskKeyboardShortcuts[i] + ')>'; }
1371
- x += '<div style="width:100%;background-color:#AAA;border-radius:4px;margin-bottom:4px;padding:4px;text-align:left;box-sizing:border-box" value=' + deskKeyboardShortcuts[i] + '>' + kt + '<img width=10 height=10 style=float:right;cursor:pointer;padding:2px;margin-left:8px src="images/trash.png" onclick=removeDeskCustomizeKey(' + deskKeyboardShortcuts[i] + ')>' + orderButtons + '</div>';
1523
+ if (fullscreen) {
1524
+ QS('DeskParent').height = null;
1525
+ QS('page_content').top = '0px';
1526
+ QS('page_content').bottom = '0px';
1527
+ if (currentDevicePanel == 1) {
1528
+ QS('p10desktop').top = '0px';
1529
+ QS('p10desktop').overflow = 'scroll';
1530
+ QS('deskarea3').top = '0px';
1531
+ QS('deskarea3').width = (desktop.m.ScreenWidth * fullscreenzoom) + 'px';
1532
+ QS('deskarea3').height = (desktop.m.ScreenHeight * fullscreenzoom) + 'px';
1533
+ QS('deskarea3')['padding-right'] = '55px';
1534
+ }
1535
+ if (currentDevicePanel == 5) {
1536
+ QS('p10terminal').top = '0px';
1537
+ QS('p10terminal').overflow = 'scroll';
1538
+ QS('termarea3').top = '0px';
1539
+ QS('termarea3').bottom = null;
1540
+ QS('termarea3').right = null;
1541
+ QS('termarea3')['padding-right'] = '55px';
1542
+ QS('termarea3')['height'] = '100%';
1543
+ }
1544
+ QS('body')['background-color'] = '#000';
1545
+ QS('p10')['background-color'] = '#000';
1546
+ } else {
1547
+ QS('DeskParent').height = '100%';
1548
+ QS('page_content').top = '50px';
1549
+ QS('page_content').bottom = '32px';
1550
+ if (currentDevicePanel == 1) {
1551
+ QS('p10desktop').top = '55px';
1552
+ QS('p10desktop').overflow = 'hidden';
1553
+ QS('deskarea3').top = '32px';
1554
+ QS('deskarea3').left = null;
1555
+ QS('deskarea3').width = '100%';
1556
+ QS('deskarea3').height = 'calc(100% - 64px)';
1557
+ QS('deskarea3')['padding-right'] = '';
1558
+ QS('DeskParent')['margin-top'] = null;
1559
+ QS('DeskParent')['margin-left'] = null;
1560
+ }
1561
+ if (currentDevicePanel == 5) {
1562
+ //xterm.setOption('fontSize', 15)
1563
+ QS('p10terminal').top = '55px';
1564
+ QS('p10terminal').overflow = 'hidden';
1565
+ Q('p10terminal').scrollTop = 0;
1566
+ Q('p10terminal').scrollLeft = 0;
1567
+ QS('termarea3').top = '32px';
1568
+ QS('termarea3').bottom = '32px';
1569
+ //QS('termarea3').right = '0px';
1570
+ QS('termarea3')['padding-right'] = null;
1571
+ QS('termarea3')['height'] = 'calc(100% - 60px)';
1572
+ }
1573
+ QS('body')['background-color'] = nightMode ? '#000' : '#FFF';
1574
+ QS('p10')['background-color'] = null;
1575
}
1373
- if (x == '') { x = '<i>' + "No keyboard shortcuts defined" + '</i>'; }
1374
- QH('d2shortcuts', x);
1576
+ if (currentDevicePanel == 1) { deskAdjust(); }
1577
}
1578
1377
- function deskCustomizeKeyDown(k) {
1378
- var i = deskKeyboardShortcuts.indexOf(k), x = deskKeyboardShortcuts[i + 1];
1379
- deskKeyboardShortcuts[i + 1] = deskKeyboardShortcuts[i];
1380
- deskKeyboardShortcuts[i] = x;
1381
- deskUpdateShortcutList();
1382
- }
1579
+ function deskAdjust() {
1580
+ if (currentDevicePanel != 1) return; // If not on desktop tab, ignore this.
1581
+ if (fullscreen) {
1582
+ QS('Desk')['margin-top'] = null;
1583
+ QS('Desk')['margin-bottom'] = null;
1584
+ QS('Desk').width = '100%';
1585
+ QS('Desk').height = '100%';
1586
+ var parentH = Q('p10desktop').clientHeight, parentW = Q('p10desktop').clientWidth;
1587
+ var deskH = Q('deskarea3').clientHeight, deskW = Q('deskarea3').clientWidth - 55;
1588
+ if (parentH > deskH) { QS('deskarea3').top = ((parentH - deskH) / 2) + 'px'; } else { QS('deskarea3').top = null; }
1589
+ if (parentW > deskW) { QS('deskarea3').left = ((parentW - deskW) / 2) + 'px'; } else { QS('deskarea3').left = null; }
1590
+ } else {
1591
+ var parentH = Q('DeskParent').clientHeight, parentW = Q('DeskParent').clientWidth;
1592
+ var deskH = Q('Desk').height, deskW = Q('Desk').width;
1593
+ var webPageFullScreen = false;
1594
1384
- function deskCustomizeKeyUp(k) {
1385
- var i = deskKeyboardShortcuts.indexOf(k), x = deskKeyboardShortcuts[i];
1386
- deskKeyboardShortcuts[i] = deskKeyboardShortcuts[i - 1];
1387
- deskKeyboardShortcuts[i - 1] = x;
1388
- deskUpdateShortcutList();
1389
- }
1595
+ // Fixed aspect ratio
1596
+ if ((parentH / parentW) > (deskH / deskW)) {
1597
+ var hNew = ((deskH * parentW) / deskW) + 'px';
1598
+ QS('Desk').height = hNew;
1599
+ QS('Desk').width = '100%';
1600
+ } else {
1601
+ var wNew = ((deskW * parentH) / deskH) + 'px';
1602
+ QS('Desk').width = wNew;
1603
+ QS('Desk').height = '100%';
1604
+ }
1605
+ QS('DeskParent').overflow = 'hidden';
1606
1391
- function removeDeskCustomizeKey(k) {
1392
- var na = [];
1393
- for (var i in deskKeyboardShortcuts) { if (deskKeyboardShortcuts[i] != k) { na.push(deskKeyboardShortcuts[i]); } }
1394
- deskKeyboardShortcuts = na;
1395
- deskUpdateShortcutList();
1607
+ // Adjust top/bottom margins
1608
+ var x = (Q('DeskParent').clientHeight - Q('Desk').clientHeight) / 2;
1609
+ QS('Desk')['margin-top'] = x + 'px';
1610
+ QS('Desk')['margin-bottom'] = x + 'px';
1611
+ }
1612
}
1613
1398
- function addDeskCustomizeKey() {
1399
- var k = parseInt(Q('d2keySelect').value);
1400
- if (Q('d1kshift').checked) { k |= 0x010000; }
1401
- if (Q('d1kalt').checked) { k |= 0x020000; }
1402
- if (Q('d1kctrl').checked) { k |= 0x080000; }
1403
- if (Q('d1kwin').checked) { k |= 0x100000; }
1404
- if ((k > 0) && (deskKeyboardShortcuts.indexOf(k) == -1)) { deskKeyboardShortcuts.push(k); deskUpdateShortcutList(); }
1614
+ function sendSpecialKeys() {
1615
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
1616
+ setDialogMode(3, "Special Keys", 3, deskSendKeys);
1617
}
1618
1407
- // Remote desktop special key combos for Windows
1408
- function deskSendKeys(ks) {
1619
+ // Save the desktop image to file
1620
+ function deskSaveImage() {
1621
+ setSessionActivity();
1622
if (xxdialogMode || desktop == null || desktop.State != 3) return;
1623
+ var d = new Date(), n = 'Desktop-' + currentNode.name + '-' + d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + '-' + ('0' + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);
1624
+ Q('Desk')['toBlob'](function (blob) { saveAs(blob, n + '.png'); });
1625
+ }
1626
1411
- // Construct the key command
1412
- if (ks == -1) { deskCustomizeKeys(); return; } // Customize
1413
- if (ks == 0x0A002E) { desktop.m.sendcad(); return; } // CTRL-ALT-DEL
1414
- //if ((desktop.contype == 1) && (ks == 0x10004C)) { desktop.sendCtrlMsg('{"action":"lock"}'); return; } // Lock desktop, WIN + L
1415
-
1416
- var flags = (ks & 0xFF0000) >> 16, key = (ks & 0xFFFF), keyArray = [], keyArray2 = [];
1417
- var amtTranslate = {
1418
- 8: 0xff08, // BackSpace
1419
- 9: 0xff09, // Tab
1420
- 13: 0xff0d, // Return or Enter
1421
- 27: 0xff1b, // Escape
1422
- 45: 0xff63, // Insert
1423
- 46: 0xffff, // Delete
1424
- 36: 0xff50, // Home
1425
- 35: 0xff57, // End
1426
- 33: 0xff55, // Page Up
1427
- 34: 0xff56, // Page Down
1428
- 37: 0xff51, // Left arrow
1429
- 38: 0xff52, // Up arrow
1430
- 39: 0xff53, // Right arrow
1431
- 40: 0xff54, // Down arrow
1432
- 112: 0xffbe, // F1
1433
- 113: 0xffbf, // F2
1434
- 114: 0xffc0, // F3
1435
- 115: 0xffc1, // F4
1436
- 116: 0xffc2, // F5
1437
- 117: 0xffc3, // F6
1438
- 118: 0xffc4, // F7
1439
- 119: 0xffc5, // F8
1440
- 120: 0xffc6, // F9
1441
- 121: 0xffc7, // F10
1442
- 122: 0xffc8, // F11
1443
- 123: 0xffc9 // F12
1444
- }
1627
+ function deskSelectScreens() {
1628
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
1629
+ var x = '', info = desktop.m.displays;
1630
+ for (var i in info) { x += '<option value=' + i + ' ' + ((desktop.m.selectedDisplay == i) ? ' selected' : '') + '>' + info[i] + '</option>'; }
1631
+ x = addHtmlValue4("Screen", '<select style=width:100% id=deskdisplays>' + x + '</select>');
1632
+ setDialogMode(2, "Screen Selection", 3, deskSelectScreensEx, x);
1633
+ }
1634
1446
- // 0x010000 = Shift
1447
- // 0x020000 = Left-Alt
1448
- // 0x080000 = Ctrl
1449
- // 0x100000 = Window
1635
+ function deskSelectScreensEx() {
1636
+ if (desktop == null || desktop.State != 3) return;
1637
+ desktop.m.SetDisplay(parseInt(Q('deskdisplays').value));
1638
+ }
1639
1451
- if (desktop.contype == 2) {
1452
- // Intel AMT
1453
- if (flags & 1) { keyArray.push([0xffe1, 1]); keyArray2.push([0xffe1, 0]); } // Shift
1454
- if (flags & 2) { keyArray.push([0xffe9, 1]); keyArray2.push([0xffe9, 0]); } // Left-alt
1455
- if (flags & 8) { keyArray.push([0xffe3, 1]); keyArray2.push([0xffe3, 0]); } // Ctrl
1456
- if (flags & 16) { keyArray.push([0xffe7, 1]); keyArray2.push([0xffe7, 0]); } // Windows key
1457
- if (amtTranslate[key]) { key = amtTranslate[key]; }
1458
- if ((key >= 65) && (key <= 90)) { key += 32; }
1459
- if (key != 0) { keyArray.push([key, 1]); keyArray2.push([key, 0]); }
1460
- keyArray2.reverse();
1461
- for (var i = 0; i < keyArray2.length; i++) { keyArray.push(keyArray2[i]); }
1462
- desktop.m.sendkey(keyArray);
1463
- } else {
1464
- // Agent desktop
1465
- if (flags & 1) { keyArray.push([desktop.m.KeyAction.DOWN, 16]); keyArray2.push([desktop.m.KeyAction.UP, 16]); } // Shift
1466
- if (flags & 2) { keyArray.push([desktop.m.KeyAction.EXDOWN, 18]); keyArray2.push([desktop.m.KeyAction.EXUP, 18]); } // Left-alt
1467
- if (flags & 8) { keyArray.push([desktop.m.KeyAction.EXDOWN, 17]); keyArray2.push([desktop.m.KeyAction.EXUP, 17]); } // Ctrl
1468
- if (flags & 16) { keyArray.push([desktop.m.KeyAction.EXDOWN, 0x5B]); keyArray2.push([desktop.m.KeyAction.EXUP, 0x5B]); } // Windows key
1469
- if (key != 0) { keyArray.push([desktop.m.KeyAction.DOWN, key]); keyArray2.push([desktop.m.KeyAction.UP, key]); }
1470
- keyArray2.reverse();
1471
- for (var i = 0; i < keyArray2.length; i++) { keyArray.push(keyArray2[i]); }
1472
- desktop.m.SendKeyMsgKC(keyArray);
1473
- }
1640
+ function deskDisplayInfo(sender, info, selDisplay, selItem) {
1641
+ var displayCount = 0;
1642
+ for (var x in info) { displayCount++; }
1643
+ QV('DeskScreens', displayCount > 1);
1644
}
1645
1646
+ function dmousedown(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) { if (fullscreen) { e.addx = Q('p10desktop').scrollLeft * (1 / fullscreenzoom); e.addy = Q('p10desktop').scrollTop * (1 / fullscreenzoom); } desktop.m.mousedown(e); } }
1647
+ function dmouseup(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) { if (fullscreen) { e.addx = Q('p10desktop').scrollLeft * (1 / fullscreenzoom); e.addy = Q('p10desktop').scrollTop * (1 / fullscreenzoom); } desktop.m.mouseup(e); } }
1648
+ function dmousemove(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null)) { if (fullscreen) { e.addx = Q('p10desktop').scrollLeft * (1 / fullscreenzoom); e.addy = Q('p10desktop').scrollTop * (1 / fullscreenzoom); } desktop.m.mousemove(e); } }
1649
+ function dmousewheel(e) { setSessionActivity(); if ((!xxdialogMode && desktop != null) && desktop.m.mousewheel) { if (fullscreen) { e.addx = Q('p10desktop').scrollLeft * (1 / fullscreenzoom); e.addy = Q('p10desktop').scrollTop * (1 / fullscreenzoom); } desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
1650
+ function drotate(x) { if (!xxdialogMode && desktop != null) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); } }
1651
+
1652
1653
//
1478
- // Terminal
1654
+ // TERMINAL
1655
//
1656
1657
+ var terminalNode;
1658
function setupTerminal() {
1659
// Setup the terminal
1483
- if (terminal != null) { terminal.Stop(); terminal = null; }
1660
+ if ((terminalNode != currentNode) && (terminal != null)) { terminal.Stop(); terminal = null; }
1661
+ terminalNode = currentNode;
1662
updateTerminalButtons();
1485
-
1486
- // Terminal special keys
1487
- var x = '';
1488
- for (var c = 1; c < 27; c++) x += '<option value=\'' + c + '\'>' + "Ctrl" + '-' + String.fromCharCode(64 + c) + ' (' + c + ')</option>';
1489
- QH('specialkeylist', x);
1663
}
1664
1665
// Show and enable the right buttons
1666
function updateTerminalButtons() {
1667
+ var mtype = (currentNode.agent == 1) ? 1 : 2;
1668
var termState = ((terminal != null) && (terminal.state != 0));
1669
+ QE('termFullScreen', (termState != 0));
1670
+
1671
+ // If we are looking at a local non-windows device, enable terminal and files capability.
1672
+ if ((terminalNode.mtype == 3) && (terminalNode.agent != null) && (terminalNode.agent.id > 4) && (features2 & 0x00000200)) { terminalNode.agent.caps = 6; }
1673
1674
// Show the right buttons
1497
- QV('disconnectbutton2span', termState == true);
1498
- QV('connectbutton2span', termState == false);
1499
- //QV('terminalSizeDropDown', termState == false);
1675
+ QV('disconnectbutton2span', (termState == true));
1676
+ QV('connectbutton2span', (termState == false) && (currentNode.agent != null) && (currentNode.agent.caps & 2));
1677
1678
// Enable buttons
1502
- QE('connectbutton2', true);
1503
-
1504
- // Key buttons
1505
- QE('ctrlcbutton', termState);
1506
- QE('ctrlxbutton', termState);
1507
- QE('escbutton', termState);
1508
- QE('bsbutton', termState);
1509
- QE('pastebutton', termState);
1510
- QE('specialkeylist', termState);
1511
- QE('specialkeylistinput', termState);
1512
-
1513
- // Terminal settings
1514
- QV('terminalSettingsButtons', (terminal) && (terminal.contype == 2));
1515
- if (terminal) {
1516
- Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
1517
- Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
1518
- Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n') ? "CR+LF" : "LF";
1679
+ var online = ((terminalNode.conn & 1) != 0) || (terminalNode.mtype == 3); // If Agent (1) connected, enable Terminal
1680
+ QE('connectbutton2', online);
1681
+
1682
+ // Enable action button if mesh type is not "local devices"
1683
+ QV('termActionsBtn', terminalNode.mtype != 3);
1684
+ if (terminalNode.mtype != 3) {
1685
+ QH('terminalCustomUpperRight', '');
1686
+ } else {
1687
+ QH('terminalCustomUpperRight', '<a style=cursor:pointer onclick=cmsshportaction(1,event)>' + format("SSH Port {0}", (terminalNode.sshport ? terminalNode.sshport : 22)) + '</a>');
1688
}
1689
+ }
1690
1521
- // Display extra buttons on legacy terminal
1522
- var xtermActive = true;
1523
- QV('termarea3xdiv', xtermActive);
1524
- QV('bsbutton', !xtermActive);
1525
- QV('pastebutton', !xtermActive);
1526
- QV('devListToolbarViewIcons2', xtermActive);
1527
- QE('termSizeList', terminal == null);
1691
+ function cmsshportaction(action) {
1692
+ if (xxdialogMode) return;
1693
+ var x = "SSH remote connection port:" + '<br /><br /><input type=text placeholder="22" inputmode="numeric" pattern="[0-9]*" onkeypress="return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)" maxlength=5 id=d10sshport type=text>';
1694
+ setDialogMode(2, "SSH Connection", 3, function () {
1695
+ // Save the new SSH port to the server
1696
+ var sshport = ((Q('d10sshport').value.length > 0) ? parseInt(Q('d10sshport').value) : 22);
1697
+ meshserver.send({ action: 'changedevice', nodeid: currentNode._id, sshport: sshport });
1698
+ }, x, currentNode);
1699
+ Q('d10sshport').focus();
1700
+ if (currentNode.sshport != null) { Q('d10sshport').value = currentNode.sshport; }
1701
}
1702
1703
// Called when the terminal state changes
@@ -1537,22 +1710,12 @@
1710
switch (state) {
1711
case 0:
1712
// Disconnected, clear the terminal
1540
- QH('termtitle', '');
1541
- QV('termRecordIcon', false);
1542
- if (xterm == null) {
1543
- xterminal.m.TermResetScreen();
1544
- xterminal.m.TermDraw();
1545
- } else {
1546
- xterm.dispose();
1547
- xterm = xtermfit = null;
1548
- }
1713
+ xterm.dispose();
1714
+ xterm = null;
1715
if (terminal != null) { terminal.Stop(); terminal = null; }
1716
break;
1717
case 3:
1552
- if (xterminal && (xterminal.serverIsRecording == true)) { QV('termRecordIcon', true); }
1553
- terminal.startTime = new Date();
1554
- if (updateSessionTimer == null) { updateSessionTimer = setInterval(updateSessionTime, 1000); }
1555
- if (xterm != null) { xterm.focus(); }
1718
+ xterm.focus();
1719
break;
1720
default:
1721
//console.log('Unhandled onTerminalStateChange state', state);
@@ -1561,24 +1724,6 @@
1724
updateTerminalButtons();
1725
}
1726
1564
- function updateSessionTime() {
1565
- // Terminal
1566
- var latencyStr = '', seconds = 0;
1567
- if (terminal && terminal.startTime) {
1568
- if (terminal.latency && (terminal.latency.current >= 0)) { latencyStr = format('{0} ms, ', terminal.latency.current); }
1569
- seconds = Math.floor((new Date() - terminal.startTime) / 1000);
1570
- QH('TermTimer', latencyStr + zeroPad(Math.floor(seconds / 3600), 2) + ':' + zeroPad((Math.floor(seconds / 60) % 60), 2) + ':' + zeroPad((seconds % 60), 2));
1571
- } else {
1572
- QH('TermTimer', '');
1573
- }
1574
-
1575
- if (terminal == null) { clearInterval(updateSessionTimer); updateSessionTimer = null; }
1576
- }
1577
-
1578
- // DEBUG
1579
- var autoConnectTerminalTimer = null;
1580
- function autoConnectTerminal(e) { if (autoConnectTerminalTimer == null) { autoConnectTerminalTimer = setInterval(connectTerminal, 100); } else { clearInterval(autoConnectTerminalTimer); autoConnectTerminalTimer = null; } }
1581
-
1727
// Handles a tunnel to a remote shell
1728
function CreateRemoteTunnel(onTunnelUpdate, options) {
1729
var obj = { protocol: 1 };
@@ -1595,20 +1740,82 @@
1740
1741
function tunnelUpdate(data) { if (typeof data == 'string') { xterm.writeUtf8(data); } else { xterm.writeUtf8(new Uint8Array(data)); } }
1742
1743
+ function sshTunnelUpdate(data) {
1744
+ if (typeof data == 'string') {
1745
+ if (data[0] == '{') {
1746
+ var j = JSON.parse(data);
1747
+ switch (j.action) {
1748
+ case 'sshauth': {
1749
+ var x = '';
1750
+ x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:150px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>')
1751
+ x += addHtmlValue("Username", '<input id=dp2user style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
1752
+ x += '<div id=d2passauth>';
1753
+ x += addHtmlValue("Password", '<input type=password id=dp2pass style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
1754
+ x += '</div><div id=d2keyauth style=display:none>';
1755
+ x += addHtmlValue("Key File", '<input type=file id=dp2key style=width:150px maxlength=64 autocomplete=off onchange=sshAuthUpdate(event) />');
1756
+ x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
1757
+ x += '</div>';
1758
+ x += '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>';
1759
+ x += '<div id=d2keyauth2 style=font-size:x-small><br />' + "Key file must be in OpenSSH format." + '</div>';
1760
+ setDialogMode(2, "Authentication", 11, sshConnectEx, x, 'ssh');
1761
+ setTimeout(sshAuthUpdate, 50);
1762
+ break;
1763
+ }
1764
+ case 'sshautoauth': {
1765
+ terminal.socket.send(JSON.stringify({ action: 'sshautoauth', cols: xterm.cols, rows: xterm.rows, width: Q('termarea3xdiv').offsetWidth, height: Q('termarea3xdiv').offsetHeight }));
1766
+ break;
1767
+ }
1768
+ case 'autherror': { p12setConsoleMsg("Authentication Error", 5000); break; }
1769
+ case 'sessionerror': { p12setConsoleMsg("Session expired", 5000); break; }
1770
+ case 'sessiontimeout': { p12setConsoleMsg("Session timeout", 5000); break; }
1771
+ }
1772
+ } else if (data[0] == '~') { xterm.writeUtf8(data.substring(1)); }
1773
+ }
1774
+ }
1775
+
1776
+ function sshAuthUpdate(e) {
1777
+ QV('d2passauth', Q('dp2authmethod').value == 1);
1778
+ QV('d2keyauth', Q('dp2authmethod').value == 2);
1779
+ QV('d2keyauth2', Q('dp2authmethod').value == 2);
1780
+ if (Q('dp2authmethod').value == 1) {
1781
+ QE('idx_dlgOkButton', (Q('dp2user').value.length > 0) && (Q('dp2pass').value.length > 0));
1782
+ } else {
1783
+ QE('idx_dlgOkButton', false);
1784
+ var ok = (Q('dp2user').value.length > 0) && (Q('dp2key').files != null) && (Q('dp2key').files.length == 1) && (Q('dp2key').files[0].size < 8000);
1785
+ if (ok == true) {
1786
+ var reader = new FileReader();
1787
+ reader.onload = function (e) {
1788
+ var validkey = ((e.target.result.indexOf('-----BEGIN OPENSSH PRIVATE KEY-----') >= 0) && (e.target.result.indexOf('-----END OPENSSH PRIVATE KEY-----') >= 0));
1789
+ QE('idx_dlgOkButton', validkey);
1790
+ }
1791
+ reader.readAsText(Q('dp2key').files[0]);
1792
+ }
1793
+ }
1794
+ }
1795
+ function sshConnectEx(b) {
1796
+ if (b == 0) {
1797
+ if (terminal != null) { connectTerminal(); } // Disconnect
1798
+ } else {
1799
+ if (Q('dp2authmethod').value == 1) {
1800
+ terminal.socket.send(JSON.stringify({ action: 'sshauth', username: Q('dp2user').value, password: Q('dp2pass').value, keep: Q('dp2keep').checked, cols: xterm.cols, rows: xterm.rows, width: Q('termarea3xdiv').offsetWidth, height: Q('termarea3xdiv').offsetHeight }));
1801
+ } else {
1802
+ var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value, keep = Q('dp2keep').checked;
1803
+ reader.onload = function (e) { terminal.socket.send(JSON.stringify({ action: 'sshauth', username: username, keypass: keypass, key: e.target.result, keep: keep, cols: xterm.cols, rows: xterm.rows, width: Q('termarea3xdiv').offsetWidth, height: Q('termarea3xdiv').offsetHeight })); }
1804
+ reader.readAsText(Q('dp2key').files[0]);
1805
+ }
1806
+ }
1807
+ }
1808
+
1809
// Send the new terminal size to the agent
1810
function xTermSendResize() {
1811
xtermResizeTimer = null;
1601
- if ((xterm != null) && (terminal != null) && (terminal.sendCtrlMsg != null)) { terminal.sendCtrlMsg(JSON.stringify({ ctrlChannel: '102938', type: 'termsize', cols: xterm.cols, rows: xterm.rows })); }
1602
- }
1603
-
1604
- // Used to translate incoming agent console messages
1605
- var agentConsoleMessages = ['', "Waiting for user to grant access...", "Denied", "Failed to start remote terminal session, {0} ({1})", "Timeout", "Received invalid network data"];
1606
- function formatAgentConsoleMessage(msg, msgid, msgargs) {
1607
- var r;
1608
- if (msgargs == null) { msgargs = []; }
1609
- while (msgargs.length < 3) { msgargs.push(''); } // We need to call the format function in a way that works with older browsers and minifier, can't use apply() or ...
1610
- if (msgid && (msgid < agentConsoleMessages.length)) { r = EscapeHtml(format(agentConsoleMessages[msgid], (msgargs[0]), (msgargs[1]), (msgargs[2]))); } else { r = EscapeHtml(msg); }
1611
- return r.split('\n').join('<br />') + '<br /><br />';
1812
+ if ((xterm != null) && (terminal != null) && (terminal.sendCtrlMsg != null)) {
1813
+ if (terminal.urlname == 'sshterminalrelay.ashx') {
1814
+ terminal.socket.send(JSON.stringify({ action: 'resize', cols: xterm.cols, rows: xterm.rows, width: Q('termarea3xdiv').offsetWidth, height: Q('termarea3xdiv').offsetHeight }));
1815
+ } else {
1816
+ terminal.sendCtrlMsg(JSON.stringify({ ctrlChannel: '102938', type: 'termsize', cols: xterm.cols, rows: xterm.rows }));
1817
+ }
1818
+ }
1819
}
1820
1821
function connectTerminal(e, contype, options) {
@@ -1617,6 +1824,7 @@
1824
// Terminal setup
1825
var termoptions = { protocol: ((options != null) && (typeof options.protocol == 'number')) ? options.protocol : 1 };
1826
if (options && options.requireLogin) { termoptions.requireLogin = true; }
1827
+
1828
/*
1829
if ([1, 2, 3, 4, 21, 22].indexOf(currentNode.agent.id) == -1) {
1830
if (Q('termSizeList').value == 1) { termoptions.cols = 80; termoptions.rows = 25; termoptions.xterm = true; }
@@ -1628,9 +1836,7 @@
1836
termoptions.xterm = true;
1837
}
1838
}
1631
- */
1839
1633
- /*
1840
// If shift is pressed
1841
if ((e && (e.shiftKey == true))) {
1842
if (currentNode.agent.id > 4) {
@@ -1639,6 +1845,13 @@
1845
if (termoptions.protocol == 1) { termoptions.protocol = 6; } // Switch to Powershell
1846
}
1847
}
1848
+
1849
+ // If the server requires a shell type
1850
+ if ((serverinfo.linuxshell) != null && (currentNode.agent.id > 4)) {
1851
+ if (serverinfo.linuxshell == 'root') { termoptions.protocol = 1; delete termoptions.requireLogin; }
1852
+ if (serverinfo.linuxshell == 'user') { termoptions.protocol = 8; delete termoptions.requireLogin; }
1853
+ if (serverinfo.linuxshell == 'login') { termoptions.protocol = 1; termoptions.requireLogin = true; }
1854
+ }
1855
*/
1856
1857
// Setup a mesh agent xterm terminal
@@ -1646,123 +1859,84 @@
1859
1860
// Setup the terminal with auto-fit
1861
if (xterm != null) { xterm.dispose(); }
1649
- xtermfit = new FitAddon.FitAddon();
1862
xterm = new Terminal();
1863
+ xtermfit = new FitAddon.FitAddon();
1864
if (xtermfit) { xterm.loadAddon(xtermfit); }
1652
- xterm.open(Q('termarea3xdiv')); // termarea3x
1653
- xterm.onData(function (data) { if (terminal != null) { terminal.sendText(data); } })
1865
+ xterm.setOption('scrollback', 0);
1866
+ //xterm.setOption('fontSize', 15);
1867
+ xterm.open(Q('termarea3xdiv'));
1868
+ xterm.onData(function (data) { if (terminal.urlname == 'sshterminalrelay.ashx') { terminal.socket.send('~' + data); } else { terminal.sendText(data); } })
1869
if (xtermfit) { xtermfit.fit(); }
1655
- xterm.onTitleChange(function (title) { QH('termtitle', ' - ' + EscapeHtml(title)); });
1870
xterm.onResize(function (size) {
1871
// Despam resize
1872
if (xtermResizeTimer) clearTimeout(xtermResizeTimer);
1873
xtermResizeTimer = setTimeout(xTermSendResize, 200);
1874
});
1875
1876
+ // Remove terminal textarea and scrollbar.
1877
+ document.getElementsByClassName('xterm-helper-textarea')[0].onfocus = () => { xterm.blur(); if (!fullscreen) toggleKeyboard(); };
1878
+ document.getElementsByClassName('xterm-viewport')[0].style.overflow = 'hidden';
1879
+
1880
// Setup a terminal tunnel to the agent
1663
- terminal = CreateAgentRedirect(null, CreateRemoteTunnel(tunnelUpdate, options), serverPublicNamePort, authCookie, null, domainUrl);
1881
+ terminal = CreateAgentRedirect(meshserver, CreateRemoteTunnel((currentNode.mtype == 3) ? sshTunnelUpdate : tunnelUpdate, termoptions), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
1882
+ if (currentNode.mtype == 3) { terminal.urlname = 'sshterminalrelay.ashx'; } // If this is a SSH session, change the URL to the SSH application relay.
1883
terminal.debugmode = debugmode;
1884
terminal.m.debugmode = debugmode;
1885
+ terminal.options = termoptions;
1886
terminal.options = { cols: xterm.cols, rows: xterm.rows };
1667
- if (options && options.requireLogin) { terminal.options.requireLogin = true; }
1668
- terminal.Start(null);
1887
+ if (termoptions.requireLogin) { terminal.options.requireLogin = true; }
1888
+ terminal.Start(terminalNode._id);
1889
terminal.onStateChanged = onTerminalStateChange;
1890
terminal.contype = 1;
1891
terminal.attemptWebRTC = false; // Never do WebRTC on terminal, because of a race condition we can't do it.
1672
- terminal.onConsoleMessageChange = function (server, msg) {
1673
- if (terminal.consoleMessage) {
1674
- Q('p12TermConsoleMsg').innerHTML += formatAgentConsoleMessage(terminal.consoleMessage, terminal.consoleMessageId, terminal.consoleMessageArgs);
1675
- QV('p12TermConsoleMsg', true);
1676
- if (p12TermConsoleMsgTimer != null) { clearTimeout(p12TermConsoleMsgTimer); }
1677
- if (terminal.consoleMessageTimeout) { p12TermConsoleMsgTimer = setTimeout(p12clearConsoleMsg, terminal.consoleMessageTimeout * 1000); }
1678
- } else {
1679
- p12clearConsoleMsg();
1680
- }
1681
- };
1892
+ terminal.onConsoleMessageChange = function () { p12setConsoleMsg(terminal.consoleMessage ? formatAgentConsoleMessage(terminal.consoleMessage, terminal.consoleMessageId, terminal.consoleMessageArgs) : null, terminal.consoleMessageTimeout); }
1893
} else {
1894
terminal.Stop();
1895
terminal = null;
1896
+ if (fullscreen) { deskToggleFull(); }
1897
}
1898
Q('connectbutton2').blur(); // Deselect the connect button so the button does not get key presses.
1899
}
1900
1689
- var terminalEmulations = ["UTF8 Terminal", "Extended ASCII", "Intel ASCII"];
1690
- function termToggleType() {
1691
- if (!terminal || xxdialogMode) return;
1692
- terminal.m.terminalEmulation = (terminal.m.terminalEmulation + 1) % 3;
1693
- Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
1694
- Q('id_ttypebutton').blur(); // Deselect the connect button so the button does not get key presses.
1695
- }
1696
-
1697
- var fxEmulations = ["Intel (F10 = ESC+[OM)", "Alternate (F10 = ESC+0)", "VT100+ (F10 = ESC+[OY)"];
1698
- function termToggleFx() {
1699
- if (!terminal || xxdialogMode) return;
1700
- terminal.m.fxEmulation = (terminal.m.fxEmulation + 1) % 3;
1701
- Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
1702
- Q('id_tfxkeysbutton').blur(); // Deselect the connect button so the button does not get key presses.
1703
- }
1704
-
1705
- function termToggleCr() {
1706
- if (!terminal || xxdialogMode) return;
1707
- if (terminal.m.lineFeed == '\n') { terminal.m.lineFeed = '\r\n'; } else { terminal.m.lineFeed = '\n'; }
1708
- Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n') ? "CR+LF" : "LF";
1709
- }
1710
-
1711
- function termSendKey(key, id) {
1712
- if (!terminal || xxdialogMode) return;
1713
- if (xterm != null) {
1714
- if (terminal.sendText) {
1715
- // MeshAgent
1716
- terminal.sendText(String.fromCharCode(key));
1717
- } else {
1718
- // CIRA
1719
- terminal.send(String.fromCharCode(key));
1720
- }
1721
- xterm.focus();
1722
- } else if (terminal != null) {
1723
- terminal.m.TermSendKey(key);
1724
- Q(id).blur(); // Deselect the connect button so the button does not get key presses.
1725
- }
1726
- }
1727
-
1728
- function showTermPasteDialog() {
1729
- if (!terminal || xxdialogMode) return;
1730
- Q('pastebutton').blur();
1731
- setDialogMode(2, "Paste", 3, showTermPasteDialogEx, '<textarea id=d2pasteText style="width:100%;height:184px;resize:none"></textarea>');
1732
- Q('d2pasteText').focus();
1733
- }
1901
+ //
1902
+ // Terminal Shortcut Keys
1903
+ //
1904
1735
- function showTermPasteDialogEx() {
1736
- if (!terminal) return;
1737
- terminal.m.TermSendKeys(Q('d2pasteText').value);
1905
+ function updateTermShortcutKeys() {
1906
+ var x = '';
1907
+ for (var i = 64; i <= 95; i++) { x += '<div class="menuButton" style="width:70px" onclick="termMenuButton(' + i + ')">' + "Ctrl + " + String.fromCharCode(i) + '</div>'; }
1908
+ QH('termButtonMenu', x);
1909
}
1910
1740
- // Send special key
1741
- function sendSpecialKey() {
1742
- if (xterm != null) {
1743
- terminal.sendText(String.fromCharCode(Q('specialkeylist').value));
1744
- xterm.focus();
1745
- } else if (terminal != null) {
1746
- terminal.m.TermSendKey(Q('specialkeylist').value);
1747
- Q('specialkeylist').blur();
1748
- Q('specialkeylistinput').blur();
1911
+ function termMenuButton(c) {
1912
+ toggleMenu(true);
1913
+ if (terminal.urlname == 'sshterminalrelay.ashx') {
1914
+ // SSH
1915
+ terminal.socket.send('~' + String.fromCharCode(c - 64));
1916
+ } else {
1917
+ // Agent
1918
+ terminal.sendText(String.fromCharCode(c - 64));
1919
}
1920
}
1921
1752
- function p12clearConsoleMsg() { QH('p12TermConsoleMsg', ''); QV('p12TermConsoleMsg', false); if (p12TermConsoleMsgTimer) { clearTimeout(p12TermConsoleMsgTimer); p12TermConsoleMsgTimer = null; } }
1753
-
1754
-
1922
1923
//
1757
- // Files
1758
- //
1924
+ // FILES
1925
+ //
1926
1927
+ var filesNode;
1928
function setupFiles() {
1929
// Setup the files tab
1762
- if (files != null) { files.Stop(); files = null; }
1930
+ var samenode = (filesNode == currentNode);
1931
+ filesNode = currentNode;
1932
+ var online = ((filesNode.conn & 1) != 0) || (filesNode.mtype == 3); // If Agent (1) connected, enable Terminal
1933
+ QE('p13Connect', online);
1934
+ if (((samenode == false) || (online == false)) && files) { files.Stop(); files = null; }
1935
+ p13setActions();
1936
}
1937
1938
function onFilesStateChange(xfiles, state) {
1939
+ setSessionActivity();
1940
p13Connect.value = (state == 0) ? "Connect" : "Disconnect";
1941
var str = StatusStrs[state];
1942
if (files.webRtcActive == true) { str += ", WebRTC"; }
@@ -1775,16 +1949,20 @@
1949
p13filetreelocation = [];
1950
QH('p13currentpath', '');
1951
QE('p13FolderUp', false);
1778
- QV('filesRecordIcon', false);
1952
p13setActions();
1953
if (files != null) { files.Stop(); files = null; }
1781
- if (xxdialogTag == 'fileMsgDialog') { setDialogMode(0); }
1954
+ if (uploadFile != null) { p13uploadFileTransferDone(); uploadFile = null; }
1955
break;
1956
case 3:
1957
+ p13filetreelocation = [];
1958
p13targetpath = '';
1959
if (files) {
1786
- files.sendText({ action: 'ls', reqid: 1, path: '' });
1787
- if (files.serverIsRecording == true) { QV('filesRecordIcon', true); }
1960
+ var filepaths = [];
1961
+ try { filepaths = JSON.parse(getstore('_devFilePaths', '[]')); } catch (ex) { }
1962
+ for (var i = 0; i < filepaths.length; i++) { if (filepaths[i].n == currentNode._id) { p13targetpath = filepaths[i].p; } }
1963
+ p13filetreelocation = p13targetpath.split('/');
1964
+ files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
1965
+ //if (files.serverIsRecording == true) { QV('filesRecordIcon', true); }
1966
}
1967
break;
1968
default:
@@ -1801,11 +1979,16 @@
1979
return obj;
1980
}
1981
1982
+ // Debug Only
1983
+ var autoConnectFilesTimer = null;
1984
+ function autoConnectFiles(e) { if (autoConnectFilesTimer == null) { autoConnectFilesTimer = setInterval(connectFiles, 100); } else { clearInterval(autoConnectFilesTimer); autoConnectFilesTimer = null; } }
1985
+
1986
function connectFiles(e) {
1987
p13clearConsoleMsg();
1988
if (!files) {
1989
// Setup a mesh agent files
1808
- files = CreateAgentRedirect(null, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, null, domainUrl);
1990
+ files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
1991
+ if (filesNode.mtype == 3) { files.urlname = 'sshfilesrelay.ashx'; } // If this is a SSH session, change the URL to the SSH application relay.
1992
files.attemptWebRTC = attemptWebRTC;
1993
files.onStateChanged = onFilesStateChange;
1994
files.onConsoleMessageChange = function () {
@@ -1818,7 +2001,7 @@
2001
p13clearConsoleMsg();
2002
}
2003
}
1821
- files.Start(null);
2004
+ files.Start(filesNode._id);
2005
} else {
2006
//QH('Term', '');
2007
files.Stop();
@@ -1833,70 +2016,78 @@
2016
var p13targetpath = null;
2017
var p13filetreelocation = [];
2018
1836
- function p13fileOperationDialogEx(b) { if ((b == 0) && (files != null)) { files.sendText({ action: 'cancel' }); } }
1837
-
2019
function p13gotFiles(data) {
2020
if ((data.length > 0) && (data.charCodeAt(0) != 123)) { p13gotDownloadBinaryData(data); return; } // This is ok because 4 first bytes is a control value.
2021
//console.log('p13gotFiles', data);
2022
try { data = JSON.parse(decode_utf8(data)); } catch (ex) { data = JSON.parse(data); }
2023
if (data.action == 'download') { p13gotDownloadCommand(data); return; }
2024
1844
- // Find file result
1845
- if (data.action == 'findfile') {
1846
- if (xxdialogTag == data.reqid) {
1847
- if (data.r == null) {
1848
- QE('d2findFilter', true);
1849
- QE('filefind_dlgOkButton', true);
1850
- xxdialogTag = null;
1851
- if (Q('d2findResults').innerHTML == '') { QH('d2findResults', '<div style=text-align:center;margin:10px><i>' + "No files found" + '</i></div>'); }
1852
- } else {
1853
- QA('d2findResults', '<div style=white-space:nowrap>' + EscapeHtml(data.r) + '</div>');
1854
- }
2025
+ // Process any SSH actions
2026
+ switch (data.action) {
2027
+ case 'sshauth': {
2028
+ var x = '';
2029
+ x += addHtmlValue("Authentication", '<select id=dp2authmethod style=width:150px onchange=sshAuthUpdate(event)><option value=1 selected>' + "Username & Password" + '</option><option value=2>' + "Username and Key" + '</option></select>')
2030
+ x += addHtmlValue("Username", '<input id=dp2user style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
2031
+ x += '<div id=d2passauth>';
2032
+ x += addHtmlValue("Password", '<input type=password id=dp2pass style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
2033
+ x += '</div><div id=d2keyauth style=display:none>';
2034
+ x += addHtmlValue("Key File", '<input type=file id=dp2key style=width:150px maxlength=64 autocomplete=off onchange=sshAuthUpdate(event) />');
2035
+ x += addHtmlValue("Key Password", '<input type=password id=dp2keypass style=width:150px maxlength=64 autocomplete=off onkeyup=sshAuthUpdate(event) />');
2036
+ x += '</div>';
2037
+ x += '<label><input id=dp2keep type=checkbox>' + "Remember credentials" + '</label>';
2038
+ x += '<div id=d2keyauth2 style=font-size:x-small><br />' + "Key file must be in OpenSSH format." + '</div>';
2039
+ setDialogMode(2, "Authentication", 11, p13sshConnectEx, x, 'ssh');
2040
+ setTimeout(sshAuthUpdate, 50);
2041
+ break;
2042
}
1856
- return;
2043
+ case 'autherror': { p13setConsoleMsg("Authentication Error", 5000); return; }
2044
+ case 'connectionerror': { p13setConsoleMsg("Connection Error", 5000); return; }
2045
+ case 'sessionerror': { p13setConsoleMsg("Session expired", 5000); return; }
2046
+ case 'sessiontimeout': { p13setConsoleMsg("Session timeout", 5000); return; }
2047
}
2048
2049
// Process file upload commands
2050
if ((data.action != null) && (data.action.startsWith('upload'))) { p13gotUploadData(data); return; }
2051
1862
- // Display a dialog message
1863
- if (data.action == 'dialogmessage') {
1864
- if ((data.msg == null) && (xxdialogTag == 'fileMsgDialog')) {
1865
- setDialogMode(0); // Close the dialog box
1866
- } else if ((data.msg == 'zipping') && ((!xxdialogMode) || (xxdialogTag == 'fileMsgDialog'))) {
1867
- // Show the dialog box message
1868
- setDialogMode(2, "File Operation", 10, p13fileOperationDialogEx, '<div style=margin:10px>' + "Compressing files..." + '<div>', 'fileMsgDialog');
1869
- } else if ((data.msg == 'zippingFile') && ((!xxdialogMode) || (xxdialogTag == 'fileMsgDialog'))) {
1870
- // Show the dialog box message
1871
- setDialogMode(2, "File Operation", 10, p13fileOperationDialogEx, '<div style=margin:10px>' + EscapeHtml(data.file) + '<div><br /><progress value=' + EscapeHtml(data.progress) + ' style=width:100% max=100 />', 'fileMsgDialog');
1872
- }
1873
- return;
1874
- }
1875
-
1876
- // Refresh file folder
1877
- if (data.action == 'refresh') { p13folderup(9999); return; }
1878
-
2052
if (data.path != null) {
1880
- data.path = data.path.replace(/\//g, '\\');
1881
- if ((p13filetree != null) && (data.path == p13filetree.path)) {
1882
- // This is an update to the same folder
1883
- var checkedNames = p13getCheckedNames();
1884
- p13filetree = data;
1885
- p13updateFiles(checkedNames);
2053
+ if (data.dir == null) {
2054
+ if (p13targetpath != '') { p13folderup(); }
2055
} else {
1887
- // Make both paths use the same seperator not start with /
1888
- var x1 = data.path.replace(/\//g, '\\'), x2 = p13targetpath.replace(/\//g, '\\');
1889
- while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
1890
- while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
1891
- if ((x1 == x2) || ((data.path == '\\') && (p13targetpath == ''))) {
1892
- // This is a different folder
2056
+ data.path = data.path.replace(/\//g, '\\');
2057
+ if ((p13filetree != null) && (data.path == p13filetree.path)) {
2058
+ // This is an update to the same folder
2059
+ var checkedNames = p13getCheckedNames();
2060
p13filetree = data;
1894
- p13updateFiles();
2061
+ p13updateFiles(checkedNames);
2062
+ } else {
2063
+ // Make both paths use the same seperator not start with /
2064
+ var x1 = data.path.replace(/\//g, '\\'), x2 = p13targetpath.replace(/\//g, '\\');
2065
+ while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
2066
+ while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
2067
+ if ((x1 == x2) || ((data.path == '\\') && (p13targetpath == ''))) {
2068
+ // This is a different folder
2069
+ p13filetree = data;
2070
+ p13updateFiles();
2071
+ }
2072
}
2073
}
2074
}
2075
}
2076
2077
+ function p13sshConnectEx(b) {
2078
+ if (b == 0) {
2079
+ if (files != null) { connectFiles(); } // Disconnect
2080
+ } else {
2081
+ if (Q('dp2authmethod').value == 1) {
2082
+ files.socket.send(JSON.stringify({ action: 'sshauth', username: Q('dp2user').value, password: Q('dp2pass').value, keep: Q('dp2keep').checked }));
2083
+ } else {
2084
+ var reader = new FileReader(), username = Q('dp2user').value, keypass = Q('dp2keypass').value, keep = Q('dp2keep').checked;
2085
+ reader.onload = function (e) { files.socket.send(JSON.stringify({ action: 'sshauth', username: username, keypass: keypass, key: e.target.result, keep: keep })); }
2086
+ reader.readAsText(Q('dp2key').files[0]);
2087
+ }
2088
+ }
2089
+ }
2090
+
2091
function p13getCheckedNames() {
2092
// Save all existing checked boxes
2093
var checkedNames = [], checkboxes = document.getElementsByName('fd');
@@ -1905,13 +2096,13 @@
2096
}
2097
2098
function p13updateFiles(checkedNames) {
1908
- var html1 = '', html2 = '', displayPath = '<a href=# style=cursor:pointer onclick="return p13folderup(0)">' + "Root" + '</a>', fullPath = 'Root';
2099
+ var html1 = '', html2 = '', displayPath = '<a style=cursor:pointer;color:black onclick=p13folderup(0)>' + "Root" + '</a>', fullPath = 'Root';
2100
2101
// Work on parsing the file path
2102
var x = p13filetree.path.split('\\');
2103
p13filetreelocation = [];
2104
for (var i in x) { if (x[i] != '') { p13filetreelocation.push(x[i]); } } // Remove empty spaces
1914
- for (var i in p13filetreelocation) { displayPath += ' / <a href=# style=cursor:pointer onclick="return p13folderup(' + (parseInt(i) + 1) + ')">' + EscapeHtml(p13filetreelocation[i]) + '</a>' } // Setup the path we display
2105
+ for (var i in p13filetreelocation) { displayPath += ' / <a style=cursor:pointer;color:black onclick=p13folderup(' + (parseInt(i) + 1) + ')>' + EscapeHtml(p13filetreelocation[i]) + '</a>' } // Setup the path we display
2106
var newlinkpath = p13filetreelocation.join('/');
2107
2108
// Sort the files
@@ -1922,37 +2113,21 @@
2113
// Figure out the name and shortname
2114
var f = filetreexx[i], name = f.n, shortname;
2115
shortname = name;
1925
- if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + ("..." + '</span>'); } else { shortname = EscapeHtml(name); }
2116
+ if (name.length > 70) { shortname = EscapeHtml(name.substring(0, 70)) + "..."; } else { shortname = EscapeHtml(name); }
2117
name = EscapeHtml(name);
2118
1928
- // Figure out the date
1929
- var fdatestr = '';
1930
- if (f.d != null) {
1931
- var fdate = new Date(f.d);
1932
- if (typeof f.d == 'number') { fdate = new Date(f.d * 1000); }
1933
- var fdatestr = printDateTime(fdate) + ' ';
1934
- }
1935
-
2119
// Figure out the size
2120
var fsize = '';
2121
if (f.s != null) { fsize = getFileSizeStr(f.s); }
2122
2123
var h = '';
2124
if (f.t < 3) {
1942
- var right = '', title = '';
1943
- h = '<div class=filelist file=999><input file=999 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'> <span style=float:right title="' + title + '">' + right + '</span><span><div class=fileIcon' + f.t + ' onclick=p13folderset("' + encodeURIComponentEx(f.nx) + '")></div><a href=# style=cursor:pointer onclick=\'return p13folderset("' + encodeURIComponentEx(f.nx) + '")\'>' + shortname + '</a></span></div>';
2125
+ var right = '';
2126
+ h = '<div class=filelist file=999><input file=999 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'> <span style=float:right>' + right + '</span><span><div class=fileIcon' + f.t + '></div><a style=cursor:pointer onclick=p13folderset("' + encodeURIComponent(f.nx) + '")>' + shortname + '</a></span></div>';
2127
} else {
2128
var link = shortname;
1946
- if (f.s > 0) {
1947
- // Local link
1948
- //link = '<a href=# style=cursor:pointer onclick="return p13downloadfile(\'' + encodeURIComponentEx(newlinkpath + '/' + name) + '\',\'' + encodeURIComponentEx(name) + '\',' + f.s + ')">' + shortname + '</a>';
1949
- // Server link
1950
- //link = '<a href="devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '" download="' + name + '" style=cursor:pointer>' + shortname + '</a>';
1951
- // Server link
1952
- //link = '<a onclick=downloadFile("devicefile.ashx?c=' + authCookie + '&m=' + currentNode.meshid.split('/')[2] + '&n=' + currentNode._id.split('/')[2] + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '","' + encodeURIComponentEx(name) + '") style=cursor:pointer>' + shortname + '</a>';
1953
- link = '<a onclick=downloadFile("devicefile.ashx?c=' + authCookie + '&f=' + encodeURIComponentEx(newlinkpath + '/' + name) + '","' + encodeURIComponentEx(name) + '") style=cursor:pointer>' + shortname + '</a>';
1954
- }
1955
- h = '<div id=fileEntry cmenu=filesContextMenu fileIndex=' + i + ' class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'> <span class=fsize>' + fdatestr + '</span><span style=float:right>' + EscapeHtml(fsize) + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
2129
+ if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" style=cursor:pointer onclick=\"p13downloadfile(\'' + encodeURIComponent(newlinkpath + '/' + name) + '\',\'' + encodeURIComponent(name) + '\',' + f.s + ')\">' + shortname + '</a>'; }
2130
+ h = '<div class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'> <span style=float:right;padding-right:4px>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
2131
}
2132
2133
if (f.t < 3) { html1 += h; } else { html2 += h; }
@@ -1972,42 +2147,31 @@
2147
2148
function p13folderset(x) {
2149
p13targetpath = joinPaths(p13filetree.path, p13filetree.dir[x].n).split('\\').join('/');
1975
- files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
2150
+ if (files) {
2151
+ p13storeCurrentPath(p13targetpath);
2152
+ files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
2153
+ }
2154
}
2155
2156
function p13folderup(x) {
2157
if (x == null) { p13filetreelocation.pop(); } else { while (p13filetreelocation.length > x) { p13filetreelocation.pop(); } }
2158
p13targetpath = p13filetreelocation.join('/');
1981
- files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
1982
- return false;
2159
+ if (files) {
2160
+ p13storeCurrentPath(p13targetpath);
2161
+ files.sendText({ action: 'ls', reqid: 1, path: p13targetpath });
2162
+ }
2163
}
2164
1985
- function p13findfile() {
1986
- if (xxdialogMode) return;
1987
- var x = addHtmlValue("Filter", '<input id=d2findFilter style="width:230px" onkeyup=p13findfileValidate() onkeydown=p13findfileDown(event) placeholder="*.txt"></input>');
1988
- x += '<div id=d2findResults style="width:100%;height:184px;background-color:white;border:1px solid black;padding:3px;overflow:scroll;margin-top:8px"></div>';
1989
- x += '<div style=margin-top:8px><input id=filefind_dlgCancelButton type=button value=' + "Close" + ' style=float:right;width:80px;margin-left:5px onclick=p13findfileCancel()>';
1990
- x += '<input id=filefind_dlgOkButton type=submit value=' + "Search" + ' style=float:right;width:80px onclick=p13findfileEx()><br /><br /></div>';
1991
- setDialogMode(2, "Find Files", 0, null, x);
1992
- p13findfileValidate();
1993
- Q('d2findFilter').focus();
1994
- }
1995
-
1996
- function p13findfileDown(e) { if (e.code == "Enter") { p13findfileEx(); } }
1997
- function p13findfileValidate() { QE('filefind_dlgOkButton', Q('d2findFilter').value.length > 0); }
1998
- function p13findfileCancel() { if (xxdialogTag != null) { files.sendText({ action: 'cancelfindfile', reqid: xxdialogTag }); } dialogclose(0) }
1999
-
2000
- function p13findfileEx(b, t) {
2001
- if (Q('d2findFilter').value.length == 0) return;
2002
- var winagent = true;//((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
2003
- var slash = winagent ? '\\' : '/';
2004
- var path = p13filetreelocation.join(slash) + slash;
2005
- if (!winagent) { path = slash + path; }
2006
- xxdialogTag = 'find:' + Math.random();
2007
- files.sendText({ action: 'findfile', reqid: xxdialogTag, path: path, filter: Q('d2findFilter').value });
2008
- QH('d2findResults', '');
2009
- QE('d2findFilter', false);
2010
- QE('filefind_dlgOkButton', false);
2165
+ // Store the current path for a given node as browser state.
2166
+ // This is so, when reconnecting to a device, you go back to the same path.
2167
+ function p13storeCurrentPath(path) {
2168
+ var filepaths = [], j = -1;
2169
+ try { filepaths = JSON.parse(getstore('_devFilePaths', '[]')); } catch (ex) { }
2170
+ for (var i = 0; i < filepaths.length; i++) { if (filepaths[i].n == currentNode._id) { j = i; } }
2171
+ if (j >= 0) { filepaths.splice(j, 1); }
2172
+ filepaths.push({ n: currentNode._id, p: path });
2173
+ while (filepaths.length > 40) { filepaths.shift(); } // Keep only 40 devices worth of paths.
2174
+ putstore('_devFilePaths', JSON.stringify(filepaths));
2175
}
2176
2177
var p13sortorder;
@@ -2027,38 +2191,38 @@
2191
}
2192
2193
function p13setActions() {
2030
- var advancedFeatures = true; //(currentNode.agent.id != 14); // Reduct file feature on some devices.
2194
+ var advancedFeatures = ((currentNode.agent) && (currentNode.agent.id != 14)); // Reduct file feature on some devices.
2195
if (p13filetree == null) {
2196
QE('p13DeleteFileButton', false);
2197
QE('p13NewFolderButton', false);
2198
QE('p13UploadButton', false);
2199
QE('p13RenameFileButton', false);
2036
- QE('p13ViewFileButton', false);
2200
QE('p13SelectAllButton', false);
2038
- Q('p13SelectAllButton').value = "Select All";
2201
+ Q('p13SelectAllButton').value = "All";
2202
QE('p13RefreshButton', false);
2040
- QE('p13FindButton', false);
2203
QE('p13CutButton', false);
2204
QE('p13CopyButton', false);
2043
- QE('p13ZipButton', false);
2205
QE('p13PasteButton', false);
2206
} else {
2207
var cc = p13getFileSelCount(), tc = p13getFileCount(), sfc = p13getFileSelCount(false); // In order: number of entires selected, number of total entries, number of selected entires that are files (not folders)
2047
- var winAgent = true; //((currentNode.agent.id > 0) && (currentNode.agent.id < 5)) || (currentNode.agent.id == 14);
2048
- QE('p13DeleteFileButton', (cc > 0) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2208
+ var winAgent = ((currentNode.agent.id > 0) && (currentNode.agent.id < 5)) || (currentNode.agent.id == 14) || (currentNode.agent.id == 34);
2209
+ QE('p13DeleteFileButton', advancedFeatures && (cc > 0) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2210
QE('p13NewFolderButton', advancedFeatures && ((p13filetreelocation.length > 0) || (winAgent == false)));
2050
- QE('p13UploadButton', ((p13filetreelocation.length > 0) || (winAgent == false) /*|| (currentNode.agent.id == 14)*/));
2211
+ QE('p13UploadButton', advancedFeatures && ((p13filetreelocation.length > 0) || (winAgent == false)));
2212
QE('p13RenameFileButton', advancedFeatures && (cc == 1) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2052
- QE('p13ViewFileButton', advancedFeatures && (cc == 1) && (sfc == 1) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2213
QE('p13SelectAllButton', tc > 0);
2054
- Q('p13SelectAllButton').value = (cc > 0 ? "Select None" : "Select All");
2214
+ Q('p13SelectAllButton').value = (cc > 0 ? "None" : "All");
2215
QE('p13RefreshButton', true);
2056
- QE('p13FindButton', advancedFeatures && ((p13filetreelocation.length > 0) || (winAgent == false)));
2057
- QE('p13CutButton', advancedFeatures && (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2058
- QE('p13CopyButton', advancedFeatures && (cc > 0) && (cc == sfc) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2059
- QE('p13ZipButton', advancedFeatures && (cc > 0) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2060
- QE('p13PasteButton', advancedFeatures && ((p13filetreelocation.length > 0) || (winAgent == false)) && ((p13clipboard != null) && (p13clipboard.length > 0)));
2216
+ QE('p13CutButton', advancedFeatures && (cc > 0) && (cc == sfc) && (currentNode.mtype != 3) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2217
+ QE('p13CopyButton', advancedFeatures && (cc > 0) && (cc == sfc) && (currentNode.mtype != 3) && ((p13filetreelocation.length > 0) || (winAgent == false)));
2218
+ QE('p13PasteButton', advancedFeatures && (currentNode.mtype != 3) && ((p13filetreelocation.length > 0) || (winAgent == false)) && ((p13clipboard != null) && (p13clipboard.length > 0)));
2219
}
2220
+ if (filesNode.mtype != 3) {
2221
+ QH('filesCustomUpperRight', '');
2222
+ } else {
2223
+ QH('filesCustomUpperRight', '<a style=cursor:pointer onclick=cmsshportaction(1,event)>' + format("SSH Port {0}", (filesNode.sshport ? filesNode.sshport : 22)) + '</a>');
2224
+ }
2225
+ QV('filesActionsBtn', filesNode.mtype != 3);
2226
}
2227
2228
function p13getFileSelCount(includeDirs) { var cc = 0; var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == '3'))) cc++; } return cc; }
@@ -2073,43 +2237,28 @@
2237
function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.sendText(t); p13folderup(999); }
2238
function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); } }
2239
function p13uploadFile() { setDialogMode(2, "Upload File", 3, p13uploadFileEx, '<input type=file name=files id=p13uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />'); updateUploadDialogOk('p13uploadinput'); }
2076
- function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q('p13uploadinput').files.length > 0); }
2240
function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
2241
function p13viewfile() {
2242
var checkboxes = document.getElementsByName('fd');
2243
for (var i = 0; i < checkboxes.length; i++) {
2244
if (checkboxes[i].checked) {
2245
if (p13filetree.dir[checkboxes[i].value].s <= 204800) {
2083
- p13downloadfile(encodeURIComponentEx(p13filetreelocation.join('/') + '/' + p13filetree.dir[checkboxes[i].value].n), encodeURIComponentEx(p13filetree.dir[checkboxes[i].value].n), p13filetree.dir[checkboxes[i].value].s, 'viewer');
2246
+ p13downloadfile(encodeURIComponent(p13filetreelocation.join('/') + '/' + p13filetree.dir[checkboxes[i].value].n), encodeURIComponent(p13filetree.dir[checkboxes[i].value].n), p13filetree.dir[checkboxes[i].value].s, 'viewer');
2247
} else { messagebox("File Editor", "Only files less than 200k can be edited."); }
2248
break;
2249
}
2250
}
2251
}
2252
2090
- function p13zipFiles() {
2091
- var inputFiles = [], checkboxes = document.getElementsByName('fd');
2092
- for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { inputFiles.push(p13filetree.dir[checkboxes[i].value].n); } }
2093
- setDialogMode(2, "Zip Filename", 3, p13zipFilesEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% value="" />', { action: 'zip', path: p13filetreelocation.join('/'), files: inputFiles });
2094
- focusTextBox('p13renameinput');
2095
- p13fileNameCheck();
2096
- }
2097
-
2098
- function p13zipFilesEx(b, tag) {
2099
- tag.output = Q('p13renameinput').value;
2100
- if (!tag.output.toLowerCase().endsWith('.zip')) { tag.output += '.zip'; }
2101
- files.sendText(tag);
2102
- }
2103
-
2253
var p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0;
2254
function p13copyFile(cut) { var checkboxes = document.getElementsByName('fd'); p13clipboard = []; p13clipboardCut = cut, p13clipboardFolder = p13targetpath; for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == '3')) { p13clipboard.push(p13filetree.dir[checkboxes[i].value].n); } } p13updateClipview(); }
2255
function p13pasteFile() {
2256
var x = '';
2257
if ((p13clipboard != null) && (p13clipboard.length > 0)) {
2258
if (p13clipboardCut == 0) {
2110
- if (p13clipboard.length > 1) { x = format("Confirm copy of {0} entries to this location?", p13clipboard.length); } else { x = format("Confirm copy of 1 entrie to this location?"); }
2259
+ if (p13clipboard.length > 1) { x = format("Confirm copy of {0} entries's to this location?", p13clipboard.length); } else { x = format("Confirm copy of 1 entrie to this location?"); }
2260
} else {
2112
- if (p13clipboard.length > 1) { x = format("Confirm move of {0} entries to this location?", p13clipboard.length); } else { x = format("Confirm move of 1 entrie to this location?"); }
2261
+ if (p13clipboard.length > 1) { x = format("Confirm move of {0} entries's to this location?", p13clipboard.length); } else { x = format("Confirm move of 1 entrie to this location?"); }
2262
}
2263
}
2264
setDialogMode(2, "Paste", 3, p13pasteFileEx, x);
@@ -2135,114 +2284,112 @@
2284
QH('p13bottomstatus', x);
2285
p13setActions();
2286
}
2138
- function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); return false; }
2139
-
2140
- function p13fileDragDrop(e) {
2141
- haltEvent(e);
2142
- QV('p13bigfail', false);
2143
- QV('p13bigok', false);
2144
- if ((e.dataTransfer == null) || (e.dataTransfer.files.length == 0) || (p13filetree == null)) return;
2145
-
2146
- // Check if these are files we can upload, remove all folders.
2147
- var files = [];
2148
- for (var i in e.dataTransfer.files) { if ((e.dataTransfer.files[i].size != null) && (e.dataTransfer.files[i].size != 0)) { files.push(e.dataTransfer.files[i]); } }
2149
- if (files.length == 0) return;
2150
-
2151
- p13doUploadFiles(files);
2152
- }
2153
-
2154
- var p13dragtimer = null;
2155
- function p13fileDragOver(e) {
2156
- haltEvent(e);
2157
- if (p13dragtimer != null) { clearTimeout(p13dragtimer); p13dragtimer = null; }
2158
- var ac = (p13filetree != null); // Set to true if we can accept the file
2159
- QV('p13bigok', ac);
2160
- QV('p13bigfail', !ac);
2161
- }
2162
-
2163
- function p13fileDragLeave(e) {
2164
- haltEvent(e);
2165
- if (e.target.id != 'p13filetable') {
2166
- QV('p13bigfail', false);
2167
- QV('p13bigok', false);
2168
- } else {
2169
- p13dragtimer = setTimeout(function () { QV('p13bigfail', false); QV('p13bigok', false); p13dragtimer = null; }, 10);
2170
- }
2171
- }
2287
+ function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); return false; } function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
2288
+ function getFileSelCount(includeDirs) { var cc = 0; var checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == "3"))) cc++; } return cc; }
2289
+ function getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fc'); return checkboxes.length; }
2290
2291
//
2292
// FILES DOWNLOAD
2293
//
2294
2177
- var gdownloadFile; // Global state for file download
2295
+ var downloadFile; // Global state for file download
2296
2297
// Called by the html page to start a download, arguments are: path, file name and file size.
2180
- function p13downloadfile(x, y, z, tag) {
2181
- if (xxdialogMode || !files) return;
2182
- gdownloadFile = { path: decodeURIComponent(x), file: decodeURIComponent(y), size: z, tsize: 0, data: '', state: 0, id: Math.random(), tag: tag }
2183
- //console.log('p13downloadFileCancel', gdownloadFile);
2184
- files.sendText({ action: 'download', sub: 'start', id: gdownloadFile.id, path: gdownloadFile.path });
2185
- setDialogMode(2, "Download File", 10, p13downloadFileCancel, '<div>' + gdownloadFile.file + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
2298
+ function p13downloadfile(x, y, z) {
2299
+ if (xxdialogMode || downloadFile || !files) return;
2300
+ downloadFile = { path: decodeURIComponent(x), file: decodeURIComponent(y), size: z, tsize: 0, data: '', state: 0, id: Math.random() }
2301
+ //console.log('p13downloadFileCancel', downloadFile);
2302
+ files.sendText({ action: 'download', sub: 'start', id: downloadFile.id, path: downloadFile.path });
2303
+ setDialogMode(2, "Download File", 10, p13downloadFileCancel, '<div>' + downloadFile.file + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
2304
}
2305
2306
// Called by the html page to cancel the download
2189
- function p13downloadFileCancel() { setDialogMode(0); files.sendText({ action: 'download', sub: 'cancel', id: gdownloadFile.id }); gdownloadFile = null; }
2307
+ function p13downloadFileCancel() { setDialogMode(0); files.sendText({ action: 'download', sub: 'cancel', id: downloadFile.id }); downloadFile = null; }
2308
2309
// Called by the transport when download control command is received
2310
function p13gotDownloadCommand(cmd) {
2311
//console.log('p13gotDownloadCommand', cmd);
2194
- if ((gdownloadFile == null) || (cmd.id != gdownloadFile.id)) return;
2195
- if (cmd.sub == 'start') { gdownloadFile.state = 1; files.sendText({ action: 'download', sub: 'startack', id: gdownloadFile.id }); }
2196
- else if (cmd.sub == 'cancel') { gdownloadFile = null; setDialogMode(0); }
2312
+ if ((downloadFile == null) || (cmd.id != downloadFile.id)) return;
2313
+ if (cmd.sub == 'start') { downloadFile.state = 1; files.sendText({ action: 'download', sub: 'startack', id: downloadFile.id }); }
2314
+ else if (cmd.sub == 'cancel') { downloadFile = null; setDialogMode(0); }
2315
}
2316
2317
// Called by the transport when binary data is received
2318
function p13gotDownloadBinaryData(data) {
2201
- if (!gdownloadFile || gdownloadFile.state == 0) return;
2319
+ if (!downloadFile || downloadFile.state == 0) return;
2320
if (data.length > 4) {
2203
- gdownloadFile.tsize += (data.length - 4); // Add to the total bytes received
2204
- gdownloadFile.data += data.substring(4); // Append the data
2205
- Q('d2progressBar').value = gdownloadFile.tsize; // Change the progress bar
2321
+ downloadFile.tsize += (data.length - 4); // Add to the total bytes received
2322
+ downloadFile.data += data.substring(4); // Append the data
2323
+ Q('d2progressBar').value = downloadFile.tsize; // Change the progress bar
2324
}
2325
if ((ReadInt(data, 0) & 1) != 0) { // Check end flag
2208
- if (gdownloadFile.tag == 'viewer') {
2209
- // View the file in the dialog box
2210
- setDialogMode(4, EscapeHtml(gdownloadFile.file), 3, p13editSaveBack, null, gdownloadFile.file);
2211
- QS('dialog').width = 'auto';
2212
- QS('dialog').bottom = '80px';
2213
- QS('dialog').top = QS('dialog').left = QS('dialog').right = '100px';
2214
- Q('d4editorarea').value = gdownloadFile.data;
2215
- gdownloadFile = null;
2216
- } else {
2217
- // Save the file to disk
2218
- saveAs(data2blob(gdownloadFile.data), gdownloadFile.file); gdownloadFile = null; setDialogMode(0); // Save the file
2219
- }
2326
+ saveAs(data2blob(downloadFile.data), downloadFile.file); downloadFile = null; setDialogMode(0); // Save the file
2327
} else {
2221
- files.sendText({ action: 'download', sub: 'ack', id: gdownloadFile.id }); // Send the ACK
2328
+ files.sendText({ action: 'download', sub: 'ack', id: downloadFile.id }); // Send the ACK
2329
}
2330
}
2331
2225
- var d4EditWrapVal = 0;
2226
- var d4EditSizeVal = 0;
2227
- function d4ToggleWrap(update) {
2228
- if (!update) { d4EditWrapVal = ++d4EditWrapVal % 2; }
2229
- Q('d4WrapButton').value = ["Wrap: ON", "Wrap: OFF"][d4EditWrapVal];
2230
- QS('d4editorarea').overflow = (d4EditWrapVal == 0) ? 'auto' : 'scroll';
2231
- QS('d4editorarea')['white-space'] = (d4EditWrapVal == 0) ? null : 'pre';
2232
- putstore('editorWrap', d4EditWrapVal);
2332
+ /*
2333
+ var downloadFile; // Global state for file download
2334
+
2335
+ // Called by the html page to start a download, arguments are: path, file name and file size.
2336
+ function p13downloadfile(x, y, z) {
2337
+ if (xxdialogMode) return;
2338
+ downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl); // Create our websocket file transport
2339
+ downloadFile.ctrlMsgAllowed = false;
2340
+ downloadFile.onStateChanged = onFileDownloadStateChange;
2341
+ downloadFile.xpath = decodeURIComponent(x);
2342
+ downloadFile.xfile = decodeURIComponent(y);
2343
+ downloadFile.xsize = z;
2344
+ downloadFile.xtsize = 0;
2345
+ downloadFile.xstate = 0;
2346
+ downloadFile.Start(filesNode._id);
2347
+ setDialogMode(2, "Download File", 10, p13downloadFileCancel, '<div>' + downloadFile.xfile + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
2348
+ }
2349
+
2350
+ // Called by the html page to cancel the download
2351
+ function p13downloadFileCancel(button, tag) {
2352
+ //console.log('p13downloadFileCancel');
2353
+ downloadFile.Stop();
2354
+ delete downloadFile;
2355
+ downloadFile = null;
2356
}
2357
2235
- function d4ToggleSize(update) {
2236
- if (!update) { d4EditSizeVal = ++d4EditSizeVal % 4; }
2237
- QS('d4editorarea')['font-size'] = ['100%', '125%', '150%', '200%'][d4EditSizeVal];
2238
- Q('d4SizeButton').value = ["Size: 100%", "Size: 125%", "Size: 150%", "Size: 200%"][d4EditSizeVal];
2239
- putstore('editorSize', d4EditSizeVal);
2358
+ // Called by the file transport to indicate when the transport connection state has changed
2359
+ function onFileDownloadStateChange(xdownloadFile, state) {
2360
+ switch (state) {
2361
+ case 0: // Transport as disconnected. If this is not part of an abort, we need to save the file
2362
+ setDialogMode(0); // Close any dialog boxes if present
2363
+ if ((downloadFile != null) && (downloadFile.xstate == 1)) { saveAs(data2blob(downloadFile.xdata), downloadFile.xfile); } // Save the file
2364
+ break;
2365
+ case 3: // Transport as connected, send a command to indicate we want to start a file download
2366
+ downloadFile.send(JSON.stringify({ action: 'download', reqid: 1, path: downloadFile.xpath }));
2367
+ break;
2368
+ default:
2369
+ console.log('Unknown onFileDownloadStateChange state', state);
2370
+ break;
2371
+ }
2372
}
2373
2242
- function p13editSaveBack(b, tag) {
2243
- var data = new TextEncoder().encode(Q('d4editorarea').value);
2244
- p13uploadFileContinue(1, [{ name: tag, size: data.byteLength, type: 'text/plain', xdata: data }]);
2374
+ // Called by the transport when data is received
2375
+ function p13gotDownloadData(data) {
2376
+ if (downloadFile.xstate == 0) { // If state is 0, this is a command confirming if the file will be transfered.
2377
+ var cmd = JSON.parse(data);
2378
+ if (cmd.action == 'downloadstart') { // Yes, the file is about to start
2379
+ downloadFile.xstate = 1; // Switch to state 1, we will start receiving the file data
2380
+ downloadFile.xdata = ''; // Start with empty data
2381
+ downloadFile.send('a'); // Send the first ACK
2382
+ } else if (cmd.action == 'downloaderror') { // Problem opening this file, cancel
2383
+ p13downloadFileCancel();
2384
+ }
2385
+ } else { // We are in the process of receiving the file
2386
+ downloadFile.xtsize += (data.length); // Add to the total bytes received
2387
+ downloadFile.xdata += data; // Append the data
2388
+ Q('d2progressBar').value = downloadFile.xtsize; // Change the progress bar
2389
+ downloadFile.send('a'); // Send the ACK
2390
+ }
2391
}
2392
+ */
2393
2394
//
2395
// FILES UPLOAD
@@ -2253,7 +2400,7 @@
2400
if (xxdialogMode) return;
2401
2402
// Check if we are going to overwrite any files
2256
- var winAgent = true;//((currentNode.agent.id > 0) && (currentNode.agent.id < 5));
2403
+ var winAgent = ((currentNode.agent.id > 0) && (currentNode.agent.id < 5)) || (currentNode.agent.id == 14) || (currentNode.agent.id == 34);
2404
var targetFiles = [], overWriteCount = 0;
2405
for (var i in p13filetree.dir) { if (winAgent) { targetFiles.push(p13filetree.dir[i].n.toLowerCase()); } else { targetFiles.push(p13filetree.dir[i].n); } }
2406
for (var i = 0; i < files.length; i++) {
@@ -2287,6 +2434,13 @@
2434
for (var n = 0; n <= 0xff; ++n) { var hexOctet = n.toString(16).padStart(2, '0'); byteToHex.push(hexOctet); }
2435
function arrayBufferToHex(arrayBuffer) { return Array.prototype.map.call(new Uint8Array(arrayBuffer), n => byteToHex[n]).join(''); }
2436
function performHash(data, f) { window.crypto.subtle.digest('SHA-384', data).then(function (v) { f(arrayBufferToHex(v)); }, function () { f(null); }); }
2437
+ function performHashOnFile(file, f) {
2438
+ // TODO: At some point, try to make this work for files of unlimited size using a digest stream
2439
+ var reader = new FileReader();
2440
+ reader.onerror = function (err) { f(null); }
2441
+ reader.onload = function () { window.crypto.subtle.digest('SHA-384', reader.result).then(function (v) { f(arrayBufferToHex(v)); }, function () { f(null); }); };
2442
+ reader.readAsArrayBuffer(file);
2443
+ }
2444
2445
// Push the next file
2446
function p13uploadNextFile() {
@@ -2298,23 +2452,15 @@
2452
Q('d2progressBar').max = file.size;
2453
Q('d2progressBar').value = 0;
2454
if (file.xdata == null) {
2301
- // Load the data
2302
- uploadFile.xreader = new FileReader();
2303
- uploadFile.xreader.onload = function () {
2304
- uploadFile.xdata = uploadFile.xreader.result;
2305
-
2306
- // If the remote file already exists and is smaller then our file, see if we can resume the trasfer
2307
- var f = null;
2308
- for (var i in p13filetree.dir) { if (p13filetree.dir[i].n == file.name) { f = p13filetree.dir[i]; } }
2309
- if ((f != null) && (f.s <= uploadFile.xreader.result.byteLength)) {
2310
- performHash(uploadFile.xreader.result.slice(0, f.s), function (hash) {
2311
- files.sendText(JSON.stringify({ action: 'uploadhash', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, tag: { h: hash.toUpperCase(), s: f.s, skip: f.s == uploadFile.xreader.result.byteLength } }));
2312
- });
2313
- } else {
2314
- files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
2315
- }
2316
- };
2317
- uploadFile.xreader.readAsArrayBuffer(file);
2455
+ uploadFile.xfile = file;
2456
+ // If the remote file already exists and is smaller then our file, see if we can resume the trasfer
2457
+ var f = null;
2458
+ for (var i in p13filetree.dir) { if (p13filetree.dir[i].n == file.name) { f = p13filetree.dir[i]; } }
2459
+ if ((f != null) && (f.s <= uploadFile.xfile.size)) {
2460
+ performHashOnFile(uploadFile.xfile, function (hash) { files.sendText(JSON.stringify({ action: 'uploadhash', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, tag: { h: hash.toUpperCase(), s: f.s, skip: f.s == uploadFile.xfile.size } })); });
2461
+ } else {
2462
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xfile.size }));
2463
+ }
2464
} else {
2465
// Data already loaded
2466
uploadFile.xdata = file.xdata;
@@ -2342,7 +2488,7 @@
2488
function p13gotUploadData(cmd) {
2489
if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
2490
switch (cmd.action) {
2345
- case 'uploadstart': { p13uploadNextPart(false); for (var i = 0; i < 8; i++) { p13uploadNextPart(true); } break; } // Send 8 more blocks of 16k to fill the websocket.
2491
+ case 'uploadstart': { uploadFile.xdataPriming = 8; p13uploadNextPart(false); break; } // Send 8 more blocks of 16k to fill the websocket.
2492
case 'uploadack': { p13uploadNextPart(false); break; }
2493
case 'uploaddone': { if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadNextFile(); } else { p13uploadFileTransferDone(); } break; }
2494
case 'uploaderror': { p13uploadFileCancel(); break; }
@@ -2354,10 +2500,10 @@
2500
p13uploadNextFile();
2501
} else {
2502
uploadFile.xptr = cmd.tag.s;
2357
- files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength, append: true }));
2503
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xfile.size, append: true }));
2504
}
2505
} else {
2360
- files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength, append: false }));
2506
+ files.sendText(JSON.stringify({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xfile.size, append: false }));
2507
}
2508
}
2509
break;
@@ -2367,15 +2513,19 @@
2513
2514
// 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.
2515
function p13uploadNextPart(dataPriming) {
2370
- var data = uploadFile.xdata, start = uploadFile.xptr;
2371
- if (start >= data.byteLength) {
2372
- files.sendText(JSON.stringify({ action: 'uploaddone', reqid: uploadFile.xfilePtr }));
2373
- } else {
2374
- var end = uploadFile.xptr + 16384;
2375
- if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
2376
- var dataslice = new Uint8Array(data.slice(start, end))
2516
+ if (uploadFile.xreader != null) return; // Data reading already in process
2517
+ if (uploadFile.xptr >= uploadFile.xfile.size) return;
2518
+ var end = uploadFile.xptr + 16384;
2519
+ if (end > uploadFile.xfile.size) { if (dataPriming == true) { return; } end = uploadFile.xfile.size; }
2520
+ uploadFile.xreader = new FileReader();
2521
+ uploadFile.xreader.onerror = function (err) { console.log(err); }
2522
+ uploadFile.xreader.onload = function () {
2523
+ var data = uploadFile.xreader.result;
2524
+ delete uploadFile.xreader;
2525
+ if (data == null) return;
2526
+ var dataslice = new Uint8Array(data)
2527
if ((dataslice[0] == 123) || (dataslice[0] == 0)) {
2378
- var datapart = new Uint8Array(end - start + 1);
2528
+ var datapart = new Uint8Array(data.byteLength + 1);
2529
datapart.set(dataslice, 1); // Add a zero char at the start of the send, this will indicate that it's not a JSON command.
2530
files.send(datapart);
2531
} else {
@@ -2383,25 +2533,44 @@
2533
}
2534
uploadFile.xptr = end;
2535
Q('d2progressBar').value = end;
2386
- }
2536
+ if (uploadFile.xptr >= uploadFile.xfile.size) {
2537
+ files.sendText(JSON.stringify({ action: 'uploaddone', reqid: uploadFile.xfilePtr }));
2538
+ } else {
2539
+ if (uploadFile.xdataPriming > 0) { uploadFile.xdataPriming--; p13uploadNextPart(true); }
2540
+ }
2541
+ };
2542
+ uploadFile.xreader.readAsArrayBuffer(uploadFile.xfile.slice(uploadFile.xptr, end));
2543
}
2544
2545
+ //
2546
+ // PANELS
2547
+ //
2548
2549
+ var xxcurrentView = -1;
2550
+ function go(x) {
2551
+ setSessionActivity();
2552
+ if (xxdialogMode || xxcurrentView == x) return;
2553
+ updateFooterMenu();
2554
+ setDialogMode(0);
2555
+ // Edit this line when adding a new screen
2556
+ for (var i = 0; i < 32; i++) { QV('p' + i, i == x); }
2557
+ xxcurrentView = x;
2558
+ }
2559
2560
//
2561
// POPUP DIALOG
2562
//
2563
2395
- // null = Hidden, 1 = Generic Message
2564
+ // undefined = Hidden, 1 = Generic Message
2565
var xxdialogMode;
2566
var xxdialogFunc;
2567
var xxdialogButtons;
2568
var xxdialogTag;
2400
- var xxcurrentView = -1;
2569
2570
// Display a dialog box
2571
// Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
2572
function setDialogMode(x, y, b, f, c, tag) {
2573
+ setSessionActivity();
2574
xxdialogMode = x;
2575
xxdialogFunc = f;
2576
xxdialogButtons = b;
@@ -2413,74 +2582,58 @@
2582
QV('idx_dlgDeleteButton', b & 4);
2583
QV('idx_dlgButtonBar', b & 7);
2584
if (y) QH('id_dialogtitle', y);
2416
- for (var i = 1; i < 8; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
2585
+ for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
2586
QV('dialog', x);
2587
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
2588
}
2589
2590
function dialogclose(x) {
2422
- var f = xxdialogFunc, b = xxdialogButtons, t = xxdialogTag;
2591
+ setSessionActivity();
2592
+ var f = xxdialogFunc;
2593
+ var b = xxdialogButtons;
2594
+ var t = xxdialogTag;
2595
setDialogMode();
2596
if (((b & 8) || x) && f) f(x, t);
2597
}
2598
2427
- function go(x) {
2428
- if (xxdialogMode) return;
2429
- QV('p11', x == 11);
2430
- QV('p12', x == 12);
2431
- QV('p13', x == 13);
2432
- xxcurrentView = x;
2433
- setupDeviceMenu();
2434
- }
2435
-
2436
- function setupDeviceMenu() {
2437
- var menus = [];
2438
- if (features & 2) { menus.push({ n: "Desktop", f: 'go(11)', s: (xxcurrentView == 11) }); }
2439
- if (features & 1) { menus.push({ n: "Terminal", f: 'go(12)', s: (xxcurrentView == 12) }); }
2440
- if (features & 4) { menus.push({ n: "Files", f: 'go(13)', s: (xxcurrentView == 13) }); }
2441
- updateFooterMenu(menus);
2442
- }
2599
2444
- function updateFooterMenu(options) {
2445
- while (options != null && options.length < 3) { options.push({ n: '' }); }
2446
- var x = '', prev = '';
2447
- if (options != null) { for (var i in options) { x += '<td style="cursor:pointer' + ((prev == '') ? '' : ';border-left:solid 1px white') + (options[i].s ? ';background-color:#487099' : '') + '" onclick="' + options[i].f + '">' + options[i].n; prev = options[i].n; } }
2448
- QH('xfooterMenu', '<tr>' + x);
2449
- }
2600
+ //
2601
+ // Generic Methods
2602
+ //
2603
2604
+ function getNodeAmtVersion(node) { if ((node == null) || (node.intelamt == null) || (typeof node.intelamt.ver != 'string')) return 0; var verSplit = node.intelamt.ver.split('.'); if (verSplit.length < 2) return 0; return parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); }
2605
+ function putstore(name, val) { try { if ((typeof (localStorage) === 'undefined') || (localStorage.getItem(name) == val)) return; if (val == null) { localStorage.removeItem(name); } else { localStorage.setItem(name, val); } } catch (e) { } if (name[0] != '_') { var s = {}; for (var i = 0, len = localStorage.length; i < len; ++i) { var k = localStorage.key(i); if (k[0] != '_') { s[k] = localStorage.getItem(k); } } meshserver.send({ action: 'userWebState', state: JSON.stringify(s) }); } }
2606
+ function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
2607
function center() { if (xtermfit) xtermfit.fit(); QS('dialog').left = ((((getDocWidth() - 300) / 2)) + 'px'); deskAdjust(); }
2608
+ function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
2609
+ function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
2610
function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
2453
- function messagebox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
2454
- function statusbox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t); }
2611
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
2456
- function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }
2457
- function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
2458
- function setSessionActivity() { sessionActivity = Date.now(); /*QH('idleTimeoutNotify', '');*/ }
2459
- function printDate(d) { return d.toLocaleDateString(urlargs.locale); }
2460
- function printTime(d) { return d.toLocaleTimeString(urlargs.locale); }
2461
- function printDateTime(d) { return d.toLocaleString(urlargs.locale); }
2462
- function printFlexDateTime(d) { if (printDate(new Date()) == printDate(d)) { return format("Expires at {0}", printTime(d)); } else { return format("Expires {0}", printDateTime(d)); } }
2463
- function getFileSizeStr(size) { if (typeof size != 'number') { size = 0; } if (size == 1) return "1 byte"; return format("{0} bytes", size); }
2464
- function encodeURIComponentEx(txt) { return encodeURIComponent(txt).replace(/'/g, '%27'); };
2612
+ function haltReturn(e) { if (e.keyCode == 13) { haltEvent(e); } }
2613
+ function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); }
2614
+ function reload() { window.location.href = window.location.href; }
2615
+ function getNodeFromId(id) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } return null; }
2616
+ function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
2617
+ function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
2618
+ function addHtmlValue4(t, v) { return '<table style=width:100%><td style=width:120px>' + t + '<td style=text-align:right><b>' + v + '</b></table>'; }
2619
+ function addLink(x, f) { return '<a style=cursor:pointer;text-decoration:none onclick=\'' + f + '\'>♦ ' + x + '</a>'; }
2620
+ function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
2621
+ function passwordcheck(p) { var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()]).{8,}/; return re.test(p); }
2622
+ function getFileSizeStr(size) { if (typeof size != 'number') { size = 0; } if (size == 1) return "1 byte"; return format('{0} bytes', size); }
2623
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
2624
function focusTextBox(x) { setTimeout(function () { Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
2625
var isFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); } })();
2626
+ function printDate(d) { return d.toLocaleDateString(args.locale); }
2627
+ function printTime(d) { return d.toLocaleTimeString(args.locale); }
2628
+ function printDateTime(d) { return d.toLocaleString(args.locale); }
2629
+ function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
2630
+ function nobreak(x) { return x.split(' ').join(' '); }
2631
+ function getUserName(userid) { if (users && users[userid] != null) return users[userid].name; return userid.split('/')[2]; }
2632
+ function addDetailItem(title, value, state) { return '<table style=width:100%><td>' + nobreak(title) + '<td style=text-align:right>' + value + '</table>'; }
2633
+ function isPrivateIP(a) { return (a.startsWith('10.') || a.startsWith('172.16.') || a.startsWith('192.168.')); }
2634
+ function encodeURIComponentEx(txt) { return encodeURIComponent(txt).replace(/'/g, '%27'); };
2635
+ function safeNewWindow(url, target) { var newWindow = window.open(url, target, 'noopener,noreferrer'); if (newWindow) { newWindow.opener = null; } }
2636
2469
- // Webkit seems to have a problem with "download" tag causing "network error", but openning the download in a hidden frame fixes it.
2470
- // So we do that for all browsers except FireFox
2471
- function downloadFile(link, name, closeDialog) {
2472
- var element = document.createElement('a');
2473
- element.setAttribute('href', link);
2474
- element.setAttribute('rel', 'noreferrer noopener');
2475
- element.setAttribute('target', 'fileDownloadFrame');
2476
- if (navigator.userAgent.indexOf('Firefox') >= 0) { element.setAttribute('download', decodeURIComponent(name ? name : '')); }
2477
- document.body.appendChild(element);
2478
- element.click();
2479
- document.body.removeChild(element);
2480
- if (closeDialog) { setDialogMode(0); }
2481
- }
2482
-
2483
- start();
2637
</script>
2638
</body>
2639
</html>
\ No newline at end of file