Revert "Remove code redundancy"
Ylian Saint-Hilaire committed
May 25, 2023 at 10:18 UTC
9d322746e60a557006ed3c7c3552091ae20e7665
2 files changed
+18399
-18367
public/styles/style.css
+40
-8
@@ -1533,44 +1533,76 @@ a {
1533
opacity: 1;
1534
}
1535
1536
-/*groups all buttons repeated code into one block*/
1537
-.lbtg{
1536
+.lb1 {
1537
+ background: url(../images/leftbar-64.png) -1px -2px;
1538
+ background-image: image-set(url(../images/leftbar-64.png) 1x, url(../images/leftbar-128.png) 2x);
1539
height: 62px;
1540
width: 62px;
1541
cursor: pointer;
1542
border: none;
1543
position: absolute;
1544
top: 6px;
1544
- left: 6px;
1545
-}
1546
-.lb1 {
1547
- background: url(../images/leftbar-64.png) -1px -2px;
1548
- background-image: image-set(url(../images/leftbar-64.png) 1x, url(../images/leftbar-128.png) 2x);
1545
+ left: 6px;
1546
}
1547
1548
.lb2 {
1549
background: url(../images/leftbar-64.png) -66px -2px;
1550
background-image: image-set(url(../images/leftbar-64.png) 1x, url(../images/leftbar-128.png) 2x);
1551
+ height: 62px;
1552
+ width: 62px;
1553
+ cursor: pointer;
1554
+ border: none;
1555
+ position: absolute;
1556
+ top: 6px;
1557
+ left: 6px;
1558
}
1559
1560
.lb3 {
1561
background: url(../images/leftbar-64.png) -130px -2px;
1562
background-image: image-set(url(../images/leftbar-64.png) 1x, url(../images/leftbar-128.png) 2x);
1563
+ height: 62px;
1564
+ width: 62px;
1565
+ cursor: pointer;
1566
+ border: none;
1567
+ position: absolute;
1568
+ top: 6px;
1569
+ left: 6px;
1570
}
1571
1572
.lb4 {
1573
background: url(../images/leftbar-64.png) -194px -2px;
1574
background-image: image-set(url(../images/leftbar-64.png) 1x, url(../images/leftbar-128.png) 2x);
1575
+ height: 62px;
1576
+ width: 62px;
1577
+ cursor: pointer;
1578
+ border: none;
1579
+ position: absolute;
1580
+ top: 6px;
1581
+ left: 6px;
1582
}
1583
1584
.lb5 {
1585
background: url(../images/leftbar-64.png) -257px -2px;
1586
background-image: image-set(url(../images/leftbar-64.png) 1x, url(../images/leftbar-128.png) 2x);
1587
+ height: 62px;
1588
+ width: 62px;
1589
+ cursor: pointer;
1590
+ border: none;
1591
+ position: absolute;
1592
+ top: 6px;
1593
+ left: 6px;
1594
}
1595
1596
.lb6 {
1597
background: url(../images/leftbar-64.png) -318px -2px;
1598
background-image: image-set(url(../images/leftbar-64.png) 1x, url(../images/leftbar-128.png) 2x);
1599
+ height: 62px;
1600
+ width: 62px;
1601
+ cursor: pointer;
1602
+ border: none;
1603
+ position: absolute;
1604
+ top: 6px;
1605
+ left: 6px;
1606
}
1607
1608
.m0 {
@@ -3246,4 +3278,4 @@ a {
3278
padding: 6px 12px;
3279
border: 1px solid #ccc;
3280
border-top: none;
3249
-}
3281
+}
\ No newline at end of file
views/default.handlebars
+18359
-18359
@@ -1,18359 +1,18359 @@
1
-<!DOCTYPE html>
2
-<html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
3
-<head>
4
- <meta http-equiv="X-UA-Compatible" content="IE=edge" />
5
- <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6
- <meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
7
- <meta name="apple-mobile-web-app-capable" content="yes" />
8
- <meta name="format-detection" content="telephone=no" />
9
- <meta name="robots" content="noindex,nofollow">
10
- <link type="image/x-icon" href="{{{domainurl}}}favicon.ico" rel="shortcut icon" />
11
- <link keeplink=1 type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS" />
12
- <link type="text/css" href="styles/ol.css" media="screen" rel="stylesheet" title="CSS" />
13
- <link type="text/css" href="styles/ol3-contextmenu.min.css" media="screen" rel="stylesheet" title="CSS" />
14
- <link type="text/css" href="styles/xterm.css" media="screen" rel="stylesheet" title="CSS" />
15
- <link type="text/css" href="styles/flatpickr.min.css" media="screen" rel="stylesheet" title="CSS">
16
- <link rel="apple-touch-icon" href="/favicon-303x303.png" />
17
- <script type="text/javascript" src="scripts/common-0.0.1{{{min}}}.js"></script>
18
- <script type="text/javascript" src="scripts/meshcentral{{{min}}}.js"></script>
19
- <script type="text/javascript" src="scripts/amt-0.2.0{{{min}}}.js"></script>
20
- <script type="text/javascript" src="scripts/amt-wsman-0.2.0{{{min}}}.js"></script>
21
- <script type="text/javascript" src="scripts/amt-desktop-0.0.2{{{min}}}.js"></script>
22
- <script type="text/javascript" src="scripts/amt-terminal-0.0.2{{{min}}}.js"></script>
23
- <script type="text/javascript" src="scripts/zlib{{{min}}}.js"></script>
24
- <script type="text/javascript" src="scripts/zlib-inflate{{{min}}}.js"></script>
25
- <script type="text/javascript" src="scripts/zlib-adler32{{{min}}}.js"></script>
26
- <script type="text/javascript" src="scripts/zlib-crc32{{{min}}}.js"></script>
27
- <script type="text/javascript" src="scripts/amt-redir-ws-0.1.0{{{min}}}.js"></script>
28
- <script type="text/javascript" src="scripts/amt-wsman-ws-0.2.0{{{min}}}.js"></script>
29
- <script type="text/javascript" src="scripts/agent-redir-ws-0.1.1{{{min}}}.js"></script>
30
- <script type="text/javascript" src="scripts/agent-redir-rtc-0.1.0{{{min}}}.js"></script>
31
- <script type="text/javascript" src="scripts/agent-desktop-0.0.2{{{min}}}.js"></script>
32
- <script type="text/javascript" src="scripts/agent-rdp-0.0.1{{{min}}}.js"></script>
33
- <script type="text/javascript" src="scripts/qrcode.min.js"></script>
34
- <script type="text/javascript" src="scripts/xterm{{{min}}}.js"></script>
35
- <script type="text/javascript" src="scripts/xterm-addon-fit{{{min}}}.js"></script>
36
- <script type="text/javascript" src="scripts/flatpickr.js"></script>
37
- <script type="text/javascript" src="mstsc/mstsc.js"></script>
38
- <script type="text/javascript" src="mstsc/keyboard.js"></script>
39
- <script type="text/javascript" src="mstsc/rle.js"></script>
40
- <script type="text/javascript" src="mstsc/client.js"></script>
41
- <script type="text/javascript" src="mstsc/canvas.js"></script>
42
- <script keeplink=1 type="text/javascript" src="scripts/u2f-api{{{min}}}.js"></script>
43
- <script keeplink=1 type="text/javascript" src="scripts/charts{{{min}}}.js"></script>
44
- <script keeplink=1 type="text/javascript" src="scripts/filesaver.min.js"></script>
45
- <script keeplink=1 type="text/javascript" src="scripts/ol{{{min}}}.js"></script>
46
- <script keeplink=1 type="text/javascript" src="scripts/ol3-contextmenu{{{min}}}.js"></script>
47
- <title>{{{title}}}</title>
48
-</head>
49
-<body id="body" oncontextmenu="handleContextMenu(event)" style="display:none;min-width:495px" onload="if (typeof(startup) !== 'undefined') startup();">
50
- <!-- right click menu -->
51
- <div id="contextMenu" class="contextMenu noselect" style="display:none">
52
- <div id="cxinfo" class="cmtext" onclick="cmaction(1,event)"><b>Information</b></div>
53
- <div id="cxdesktop" class="cmtext" onclick="cmaction(3,event)">Desktop</div>
54
- <div id="cxterminal" class="cmtext" onclick="cmaction(2,event)">Terminal</div>
55
- <div id="cxfiles" class="cmtext" onclick="cmaction(4,event)">Files</div>
56
- <div id="cxevents" class="cmtext" onclick="cmaction(5,event)">Events</div>
57
- <div id="cxdetails" class="cmtext" onclick="cmaction(6,event)">Details</div>
58
- <div id="cxconsole" class="cmtext" onclick="cmaction(7,event)">Console</div>
59
- <div id="cxwebrdp" class="cmtext" onclick="cmaction(11,event)">Web-RDP</div>
60
- <div id="cxwebvnc" class="cmtext" onclick="cmaction(12,event)">Web-VNC</div>
61
- <div id="cxwebssh" class="cmtext" onclick="cmaction(13,event)">Web-SSH</div>
62
- <div id="cxplugins" class="cmtext" onclick="cmaction(8,event)" style="display:none">Plugins</div>
63
- <hr id="cxmgroupsplit" />
64
- <div id="cxstar" class="cmtext" onclick="cmaction(10,event)" style="display:none">Toggle Star</div>
65
- <div id="cxmdesktop" class="cmtext" onclick="cmaction(9,event)" style="display:none">Multi-Desktop</div>
66
- </div>
67
- <div id="meshContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
68
- <div id="cxselectall" class="cmtext" onclick="cmmeshaction(1,event)">Select All</div>
69
- <div id="cxselectnone" class="cmtext" onclick="cmmeshaction(2,event)">Select None</div>
70
- <!--
71
- <hr id="cxmgroupsplit2" style="display:none" />
72
- <div id="cxmmdesktop" class="cmtext" style="display:none" onclick="cmmeshaction(3,event)">Multi-Desktop</div>
73
- -->
74
- </div>
75
- <div id="filesShellContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
76
- <div class="cmtext" onclick="cmconnectfilesaction()">Ask Consent</div>
77
- </div>
78
- <div id="termShellContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
79
- <div class="cmtext" onclick="cmtermaction(1,0,event)"><b>Admin Shell</b></div>
80
- <div class="cmtext" onclick="cmtermaction(6,0,event)">Admin PowerShell</div>
81
- <div class="cmtext" onclick="cmtermaction(8,0,event)">User Shell</div>
82
- <div class="cmtext" onclick="cmtermaction(9,0,event)">User PowerShell</div>
83
- <div class="cmtext" onclick="cmtermaction(1,0x10,event)">Ask Admin Shell</div>
84
- <div class="cmtext" onclick="cmtermaction(6,0x10,event)">Ask Admin PowerShell</div>
85
- <div class="cmtext" onclick="cmtermaction(8,0x10,event)">Ask User Shell</div>
86
- <div class="cmtext" onclick="cmtermaction(9,0x10,event)">Ask User PowerShell</div>
87
- </div>
88
- <div id="termShellContextMenu2" class="contextMenu noselect" style="display:none;min-width:0px">
89
- <div class="cmtext" onclick="cmtermaction(8,0,event)"><b>User Shell</b></div>
90
- <div class="cmtext" onclick="cmtermaction(9,0,event)">User PowerShell</div>
91
- </div>
92
- <div id="termShellContextMenuLinux" class="contextMenu noselect" style="display:none;min-width:0px">
93
- <div class="cmtext" onclick="cmtermaction(1,0,event)"><b>Root Shell</b></div>
94
- <div class="cmtext" onclick="cmtermaction(8,0,event)">User Shell</div>
95
- <div class="cmtext" onclick="cmtermaction(100,0,event)">Login Shell</div>
96
- </div>
97
- <div id="deskConnectContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
98
- <div class="cmtext" onclick="cmdeskaction(1,event)">Ask Consent + Bar</div>
99
- <div class="cmtext" onclick="cmdeskaction(2,event)">Ask Consent</div>
100
- <div class="cmtext" onclick="cmdeskaction(3,event)">Privacy Bar</div>
101
- </div>
102
- <div id="deskDisconnectContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
103
- <div class="cmtext" onclick="cmdeskaction(10,event)">Disconnect and Lock</div>
104
- <div class="cmtext" onclick="cmdeskaction(11,event)">Disconnect</div>
105
- </div>
106
- <div id="altPortContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
107
- <div class="cmtext" onclick="cmaltportaction(1,event)">Alternate Port</div>
108
- </div>
109
- <div id="sshPortContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
110
- <div class="cmtext" onclick="cmsshportaction(1,event)">Alternate Port</div>
111
- </div>
112
- <div id="rfbPortContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
113
- <div class="cmtext" onclick="cmrfbportaction(1,event)">Alternate Port</div>
114
- </div>
115
- <div id="httpPortContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
116
- <div class="cmtext" onclick="cmhttpportaction(1,event)">Alternate Port</div>
117
- </div>
118
- <div id="httpsPortContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
119
- <div class="cmtext" onclick="cmhttpsportaction(1,event)">Alternate Port</div>
120
- </div>
121
- <div id="filesContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
122
- <div class="cmtext" onclick="cmfilesaction(1,event)">Rename</div>
123
- <div class="cmtext" onclick="cmfilesaction(2,event)">Edit</div>
124
- <div class="cmtext" onclick="cmfilesaction(3,event)">Delete</div>
125
- </div>
126
- <div id="expandAllContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
127
- <div class="cmtext" onclick="cmexpandaction(1,event)">Expand All</div>
128
- <div class="cmtext" onclick="cmexpandaction(2,event)">Collapse All</div>
129
- </div>
130
- <div id="deskPlayerContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
131
- <div class="cmtext" onclick="cmdeskplayeraction(1,event)">Open Player...</div>
132
- </div>
133
- <div id="deskKeyShortcutContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
134
- <div class="cmtext" onclick="cmdeskshortcutaction(1,event)">Customize...</div>
135
- </div>
136
- <div id="deskPreConfigShortcutContextMenu" class="contextMenu noselect" style="display:none;min-width:0px;max-height:calc(80% - 50px);overflow-y:auto">
137
- <span id="deskPreConfigShortcutContextMenu1"></span>
138
- <span id="deskPreConfigShortcutContextMenu2"></span>
139
- <div class="cmtext" onclick="cmdeskpreconfigtypeaction(-1,event)">Customize...</div>
140
- </div>
141
- <div id="deskPreConfigScriptContextMenu" class="contextMenu noselect" style="display:none;min-width:0px;max-height:calc(80% - 50px);overflow-y:auto">
142
- <span id="deskPreConfigScriptContextMenu1"></span>
143
- <span id="deskPreConfigScriptContextMenu2"></span>
144
- </div>
145
- <!--
146
- <div id="pluginTabContextMenu" class="contextMenu noselect" style="display:none;min-width:0px">
147
- <div id="cxclose" class="cmtext" onclick="pluginTabClose(event)">Close Tab</div>
148
- </div>
149
- -->
150
- <!-- main page -->
151
- <div id=container>
152
- <div id="notifiyBox" class="notifiyBox" style="display:none"></div>
153
- <div id=masthead class=noselect>
154
- <div style="float:left">{{{titlehtml}}}</div>
155
- <div class="title">{{{title1}}}</div>
156
- <div class="title2">{{{title2}}}</div>
157
- <div style="float:right">
158
- <div id=notificationCount onclick="clickNotificationIcon()" class="unselectable" style="display: none;" title="Click to view current notifications">0</div>
159
- </div>
160
- <p id="logoutControl"><span id=logoutControlSpan class="logoncontrolspan"></span><span id=idleTimeoutNotify style="color:yellow"></span></p>
161
- </div>
162
- <div id="page_leftbar">
163
- <div style="height:16px"></div>
164
- <div id=LeftMenuMyDevices tabindex=0 class="lbbutton lbbuttonsel" title="My Devices" onclick=go(1,event) onkeypress="if (event.key=='Enter') { go(1); }">
165
- <div class="lb2 lbtng"></div>
166
- </div>
167
- <div id=LeftMenuMyAccount tabindex=0 class="lbbutton" title="My Account" onclick=go(2,event) onkeypress="if (event.key=='Enter') { go(2); }">
168
- <div class="lb1 lbtng"></div>
169
- </div>
170
- <div id=LeftMenuMyEvents tabindex=0 class="lbbutton" title="My Events" onclick=go(3,event) onkeypress="if (event.key=='Enter') { go(3); }">
171
- <div class="lb3 lbtng"></div>
172
- </div>
173
- <div id=LeftMenuMyFiles tabindex=0 class="lbbutton" style="display:none" title="My Files" onclick=go(5,event) onkeypress="if (event.key=='Enter') { go(5); }">
174
- <div class="lb4 lbtng"></div>
175
- </div>
176
- <div id=LeftMenuMyUsers tabindex=0 class="lbbutton" style="display:none" title="My Users" onclick=go(4,event) onkeypress="if (event.key=='Enter') { go(4); }">
177
- <div class="lb5 lbtng"></div>
178
- </div>
179
- <div id=LeftMenuMyServer tabindex=0 class="lbbutton" style="display:none" title="My Server" onclick=go(6,event) onkeypress="if (event.key=='Enter') { go(6); }">
180
- <div class="lb6 lbtng"></div>
181
- </div>
182
- </div>
183
- <div id=topbar class=noselect>
184
- <div>
185
- <div style="position:relative">
186
- <span id=logoutControlSpan2></span>
187
- <div tabindex=0 id=uiMenuButton title="User interface selection" onclick="showUserInterfaceSelectMenu()" onkeypress="if (event.key == 'Enter') showUserInterfaceSelectMenu()">
188
- ♦
189
- <div id=uiMenu style="display:none">
190
- <table>
191
- <tr>
192
- <td>
193
- <div tabindex=0 id=uiViewButton1 class=uiSelector onclick=userInterfaceSelectMenu(1) title="Left bar interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(1)"><div class="uiSelector1"></div></div>
194
- <div tabindex=0 id=uiViewButton2 class=uiSelector onclick=userInterfaceSelectMenu(2) title="Top bar interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(2)"><div class="uiSelector2"></div></div>
195
- <div tabindex=0 id=uiViewButton3 class=uiSelector onclick=userInterfaceSelectMenu(3) title="Fixed width interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(3)"><div class="uiSelector3"></div></div>
196
- </td>
197
- <td>
198
- <div tabindex=0 id=uiViewButton6 class=uiSelector onclick="showNotes(false)" title="Personal Notes" onkeypress="if (event.key == 'Enter') showNotes(false)"><div class="uiSelector6"></div></div>
199
- <div tabindex=0 id=uiViewButton4 class=uiSelector onclick=toggleNightMode() title="Toggle night mode" onkeypress="if (event.key == 'Enter') toggleNightMode()"><div class="uiSelector4"></div></div>
200
- <div tabindex=0 id=uiViewButton5 class=uiSelector onclick=toggleFooterBarMode() title="Toggle footer bar" onkeypress="if (event.key == 'Enter') toggleFooterBarMode()"><div class="uiSelector5"></div></div>
201
- </td>
202
- </tr>
203
- </table>
204
- </div>
205
- </div>
206
- <table id=MainMenuSpan cellpadding=0 cellspacing=0 class=style1>
207
- <tr>
208
- <td tabindex=0 id=MainMenuMyDevices class="topbar_td style3x" onclick=go(1,event) onkeypress="if (event.key == 'Enter') go(1)">My Devices</td>
209
- <td tabindex=0 id=MainMenuMyAccount class="topbar_td style3x" onclick=go(2,event) onkeypress="if (event.key == 'Enter') go(2)">My Account</td>
210
- <td tabindex=0 id=MainMenuMyEvents class="topbar_td style3x" onclick=go(3,event) onkeypress="if (event.key == 'Enter') go(3)">My Events</td>
211
- <td tabindex=0 id=MainMenuMyFiles class="topbar_td style3x" onclick=go(5,event) onkeypress="if (event.key == 'Enter') go(5)">My Files</td>
212
- <td tabindex=0 id=MainMenuMyUsers class="topbar_td style3x" onclick=go(4,event) onkeypress="if (event.key == 'Enter') go(4)">My Users</td>
213
- <td tabindex=0 id=MainMenuMyServer class="topbar_td style3x" onclick=go(6,event) onkeypress="if (event.key == 'Enter') go(6)">My Server</td>
214
- <td class="topbar_td_end style3"> </td>
215
- </tr>
216
- </table>
217
- <div id=MainSubMenuSpan style="display:none">
218
- <table id=MainSubMenu cellpadding=0 cellspacing=0 class=style1>
219
- <tr>
220
- <td tabindex=0 id=MainDev class="topbar_td style3x" onclick=go(10,event) onkeypress="if (event.key == 'Enter') go(10)">General</td>
221
- <td tabindex=0 id=MainDevDesktop class="topbar_td style3x" onclick=go(11,event) onkeypress="if (event.key == 'Enter') go(11)">Desktop</td>
222
- <td tabindex=0 id=MainDevTerminal class="topbar_td style3x" onclick=go(12,event) onkeypress="if (event.key == 'Enter') go(12)">Terminal</td>
223
- <td tabindex=0 id=MainDevFiles class="topbar_td style3x" onclick=go(13,event) onkeypress="if (event.key == 'Enter') go(13)">Files</td>
224
- <td tabindex=0 id=MainDevEvents class="topbar_td style3x" onclick=go(16,event) onkeypress="if (event.key == 'Enter') go(16)">Events</td>
225
- <td tabindex=0 id=MainDevInfo class="topbar_td style3x" onclick=go(17,event) onkeypress="if (event.key == 'Enter') go(17)">Details</td>
226
- <td tabindex=0 id=MainDevAmt class="topbar_td style3x" onclick=go(14,event) onkeypress="if (event.key == 'Enter') go(14)">Intel®AMT</td>
227
- <td tabindex=0 id=MainDevConsole class="topbar_td style3x" onclick=go(15,event) onkeypress="if (event.key == 'Enter') go(15)">Console</td>
228
- <td tabindex=0 id=MainDevPlugins class="topbar_td style3x" onclick=go(19,event) onkeypress="if (event.key == 'Enter') go(19)">Plugins</td>
229
- <td class="topbar_td_end style3"> </td>
230
- </tr>
231
- </table>
232
- </div>
233
- <div id=MeshSubMenuSpan style="display:none">
234
- <table id=MeshSubMenu cellpadding=0 cellspacing=0 class=style1>
235
- <tr>
236
- <td tabindex=0 id=MeshGeneral class="topbar_td style3x" onclick=go(20,event) onkeypress="if (event.key == 'Enter') go(20)">General</td>
237
- <td tabindex=0 id=MeshSummary class="topbar_td style3x" onclick=go(21,event) onkeypress="if (event.key == 'Enter') go(21)">Summary</td>
238
- <td class="topbar_td_end style3"> </td>
239
- </tr>
240
- </table>
241
- </div>
242
- <div id=EventsSubMenuSpan style="display:none">
243
- <table id=EventsSubMenu cellpadding=0 cellspacing=0 class=style1>
244
- <tr>
245
- <td tabindex=0 id=EventsLive class="topbar_td style3x" onclick=go(3,event) onkeypress="if (event.key == 'Enter') go(3)">Events</td>
246
- <td tabindex=0 id=EventsReport class="topbar_td style3x" onclick=go(60,event) onkeypress="if (event.key == 'Enter') go(60)">Reports</td>
247
- <td class="topbar_td_end style3"> </td>
248
- </tr>
249
- </table>
250
- </div>
251
- <div id=UserSubMenuSpan style="display:none">
252
- <table id=UserSubMenu cellpadding=0 cellspacing=0 class=style1>
253
- <tr>
254
- <td tabindex=0 id=UserGeneral class="topbar_td style3x" onclick=go(30,event) onkeypress="if (event.key == 'Enter') go(30)">General</td>
255
- <td tabindex=0 id=UserEvents class="topbar_td style3x" onclick=go(31,event) onkeypress="if (event.key == 'Enter') go(31)">Events</td>
256
- <td class="topbar_td_end style3"> </td>
257
- </tr>
258
- </table>
259
- </div>
260
- <div id=UsersSubMenuSpan style="display:none">
261
- <table id=UsersSubMenu cellpadding=0 cellspacing=0 class=style1>
262
- <tr>
263
- <td tabindex=0 id=UsersGeneral class="topbar_td style3x" onclick=go(4,event) onkeypress="if (event.key == 'Enter') go(4)">Users</td>
264
- <td tabindex=0 id=UsersGroups class="topbar_td style3x" onclick=go(50,event) onkeypress="if (event.key == 'Enter') go(50)">Groups</td>
265
- <td tabindex=0 id=UsersRecordings class="topbar_td style3x" onclick=go(52,event) onkeypress="if (event.key == 'Enter') go(52)">Recordings</td>
266
- <td class="topbar_td_end style3"> </td>
267
- </tr>
268
- </table>
269
- </div>
270
- <div id=ServerSubMenuSpan style="display:none">
271
- <table id=ServerSubMenu cellpadding=0 cellspacing=0 class=style1>
272
- <tr>
273
- <td tabindex=0 id=ServerGeneral class="topbar_td style3x" onclick=go(6,event) onkeypress="if (event.key == 'Enter') go(6)">General</td>
274
- <td tabindex=0 id=ServerStats class="topbar_td style3x" onclick=go(40,event) onkeypress="if (event.key == 'Enter') go(40)">Stats</td>
275
- <td tabindex=0 id=ServerConsole class="topbar_td style3x" onclick=go(115,event) onkeypress="if (event.key == 'Enter') go(115)">Console</td>
276
- <td tabindex=0 id=ServerTrace class="topbar_td style3x" onclick=go(41,event) onkeypress="if (event.key == 'Enter') go(41)">Trace</td>
277
- <td tabindex=0 id=ServerPlugins class="topbar_td style3x" onclick=go(42,event) onkeypress="if (event.key == 'Enter') go(42)">Plugins</td>
278
- <td class="topbar_td_end style3"> </td>
279
- </tr>
280
- </table>
281
- </div>
282
- <div id=UserDummyMenuSpan>
283
- <table id=UserDummyMenu cellpadding=0 cellspacing=0 class=style1>
284
- <tr><td class=style3 style=""> </td></tr>
285
- </table>
286
- </div>
287
- </div>
288
- </div>
289
- </div>
290
- <div id="column_l">
291
- <div id=p0 style="display:none">
292
- <div id=p0message><span id=p0span>Server disconnected</span>, <href onclick=reload() style=cursor:pointer><u>click to reconnect</u></href>.</div>
293
- </div>
294
- <div id=p1 style="display:none">
295
- <div id="p1title">
296
- <div style="display:none" id="devListToolbarViewIcons">
297
- <div id=devViewPageState style="float:left;line-height:32px;height:32px;font-size:16px;display:none"></div>
298
- <div tabindex=0 id=devViewPageButton1 class=viewSelector onclick=onDeviceViewPageChange(1) onkeypress="if (event.key == 'Enter') { onDeviceViewPageChange(1); }" title="Go to first page" style="display:none"><div class="viewSelector9"></div></div>
299
- <div tabindex=0 id=devViewPageButton2 class=viewSelector onclick=onDeviceViewPageChange(2) onkeypress="if (event.key == 'Enter') { onDeviceViewPageChange(2); }" title="Go to previous page" style="display:none"><div class="viewSelector10"></div></div>
300
- <div tabindex=0 id=devViewPageButton3 class=viewSelector onclick=onDeviceViewPageChange(3) onkeypress="if (event.key == 'Enter') { onDeviceViewPageChange(3); }" title="Go to next page" style="display:none"><div class="viewSelector11"></div></div>
301
- <div tabindex=0 id=devViewPageButton4 class=viewSelector onclick=onDeviceViewPageChange(4) onkeypress="if (event.key == 'Enter') { onDeviceViewPageChange(4); }" title="Go to last page" style="display:none;margin-right:12px"><div class="viewSelector8"></div></div>
302
- <div tabindex=0 id=devViewButton1 class=viewSelector onclick=onDeviceViewChange(1) onkeypress="if (event.key == 'Enter') { onDeviceViewChange(1); }" title="Columns"><div class="viewSelector2"></div></div>
303
- <div tabindex=0 id=devViewButton2 class=viewSelector onclick=onDeviceViewChange(2) onkeypress="if (event.key == 'Enter') { onDeviceViewChange(2); }" title="List"><div class="viewSelector1"></div></div>
304
- <div tabindex=0 id=devViewButton3 class=viewSelector onclick=onDeviceViewChange(3) onkeypress="if (event.key == 'Enter') { onDeviceViewChange(3); }" title="Desktops"><div class="viewSelector3"></div></div>
305
- <div tabindex=0 id=devViewButton5 class=viewSelector onclick=onDeviceViewChange(5) onkeypress="if (event.key == 'Enter') { onDeviceViewChange(5); }" title="Desktops"><div class="viewSelector7"></div></div>
306
- <div tabindex=0 id=devViewButton4 class=viewSelector onclick=onDeviceViewChange(4) onkeypress="if (event.key == 'Enter') { onDeviceViewChange(4); }" title="Map" style="display:none"><div class="viewSelector4"></div></div>
307
- </div><div><h1>My Devices</h1></div>
308
- </div>
309
- <table id="devListToolbarSpan" class="noselect">
310
- <tr>
311
- <td class=h1></td>
312
- <td id=devListToolbar class=style14 style="display:none">
313
- <img style="cursor:pointer;margin-top:4px;display:none" title="Collapse All" id="CollapseAllButton" src="images/icon-collapse.png" loading=lazy width=9 height=11 onclick="cmexpandaction(2)" />
314
- <img style="cursor:pointer;margin-top:4px;display:none" title="Expand All" id="ExpandAllButton" src="images/icon-expand.png" loading=lazy width=9 height=11 onclick="cmexpandaction(1)" />
315
- <input type=button id=SelectAllButton onclick="selectallButtonFunction();" value="Select All" />
316
- <input type=button id=GroupActionButton disabled="disabled" value="Group Action" onclick=groupActionFunction() />
317
- <input id=SearchInput type=search autocomplete=off placeholder=Filter onchange=onDeviceSearchChanged(event) onclick=onDeviceSearchChanged(event) onkeyup=onDeviceSearchChanged(event) onfocus=onSearchFocus(1) onblur=onSearchFocus(0) title="Filter: user:xxx or u:xxx ip:xxx group:xxx or g:xxx tag:xxx or t: xxx atag:xxx or a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc:noupdate wsc:nofirewall wsc:any"/>
318
- <span id=SearchInputClearButton style="display:none;position:relative"><img src="images/x16.png" type="button" onclick="clearDeviceSearch()" style="position:absolute;cursor:pointer;left:-18px;top:-8px" srcset="images/x32.png 2x"/></span>
319
- <select id=DevFilterSelect onchange=onOnlineCheckBox(event) title="Device Filter">
320
- <option value=0>All</option>
321
- <option value=1>Online</option>
322
- <option value=5>Offline</option>
323
- <option value=2>Sessions</option>
324
- <option value=3>Starred</option>
325
- <option value=4>Intel® AMT</option>
326
- <option value=6>Help</option>
327
- <option value=7>Tagged</option>
328
- <option value=8>Untagged</option>
329
- </select>
330
- <label><input type=checkbox id=RealNameCheckBox onclick=onRealNameCheckBox() /><span title="Show devices operating system name">OS Name</span></label>
331
- <label style="display:none"><input type=checkbox id=OnlineCheckBox onclick=onOnlineCheckBox(event) /><span title="Only show devices that are online">Online</span></label>
332
- <span id="devsCustomUIBar"></span>
333
- </td>
334
- <td id=kvmListToolbar class=style14 style="display:none">
335
- <img style="cursor:pointer;margin-top:4px;display:none" title="Collapse All" id="CollapseAllButton2" src="images/icon-collapse.png" loading=lazy width=9 height=11 onclick="cmexpandaction(2)" />
336
- <img style="cursor:pointer;margin-top:4px;display:none" title="Expand All" id="ExpandAllButton2" src="images/icon-expand.png" loading=lazy width=9 height=11 onclick="cmexpandaction(1)" />
337
- <input type="button" onclick="connectAllKvmFunction()" value="Connect All" />
338
- <input type="button" onclick="disconnectAllKvmFunction()" value="Disconnect All" />
339
- <label><input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" title="Automatic connect" />Auto </label>
340
- <input type="button" onclick="showMultiDesktopSettings()" value="Settings" />
341
- <input id=KvmSearchInput type=search placeholder=Filter onchange=onDeviceSearchChanged(event) onclick=onDeviceSearchChanged(event) onkeyup=onDeviceSearchChanged(event) autocomplete=off onfocus=onSearchFocus(1) onblur=onSearchFocus(0) />
342
- <span id=KvmSearchInputClearButton style="display:none;position:relative"><img src="images/x16.png" type="button" onclick="clearDeviceSearch()" style="position:absolute;cursor:pointer;left:-18px;top:-8px" srcset="images/x32.png 2x" /></span>
343
- </td>
344
- <td id=devMapToolbar class=style14 style="display:none">
345
- <input type=search id=mapSearchLocation placeholder="Search Location" onfocus=onMapSearchFocus(1) onblur=onMapSearchFocus(0) />
346
- <input type=button value=Search title="Search for location" onclick=getSearchLocation() />
347
- <input type=button id=refreshmap title="Reset map view" value=Reset onclick=refreshMap(false,true) />
348
- </td>
349
- <td class="auto-style1" style=height:100%>
350
- <img style="display:none;cursor:pointer;margin-top:3px" id=devListToolbarSettings src="images/icon-gear.png" loading=lazy width=16 height=16 onclick="onDeviceViewSettings()" />
351
- <div style="display:none" id=devListToolbarView>
352
- View
353
- <select id=viewselect onchange=onDeviceViewChange()>
354
- <option value=1>Columns</option>
355
- <option value=2>List</option>
356
- <option value=3>Desktops Fixed Width</option>
357
- <option id=viewselectmapoption value=4 style="display:none">Map</option>
358
- <option value=5>Desktops</option>
359
- </select>
360
- </div>
361
- <div style="display:none" id=devListToolbarSort>
362
- Sort
363
- <select id=sortselect onchange=mainUpdate(6)>
364
- <option>Group</option>
365
- <option>Power</option>
366
- <option>Device</option>
367
- <option>Tags</option>
368
- <option>Group-Tags</option>
369
- <option>Last Seen</option>
370
- </select>
371
-
372
- </div>
373
- <div style="display:none" id=devListToolbarSize>
374
- Size
375
- <select id=sizeselect onchange=onDeviceViewChange()>
376
- <option value=0>Small</option>
377
- <option value=1>Medium</option>
378
- <option value=2>Large</option>
379
- </select>
380
-
381
- </div>
382
- </td>
383
- <td class=h2></td>
384
- </tr>
385
- </table>
386
- <div id=NoMeshesPanel style="display:none">
387
- <table>
388
- <tr>
389
- <td valign="top" style="width:50px">
390
- <img src="images/info.png" loading="lazy" width="47" height="48" />
391
- </td>
392
- <td>
393
- <div id="getStarted1">To get started, <a href=# onclick="return account_createMesh()"><strong>click here to create a device group</strong></a>.</div>
394
- <div id="getStarted2">No device groups.</div>
395
- </td>
396
- </tr>
397
- </table>
398
- </div>
399
- <div id="xdevices" class="noselect" style="display:none" onscroll="onDevicesScroll()"></div>
400
- <div id="xdevicesmap" style="display:none">
401
- <div id=xmapSearchResultsDlg style="display:none">
402
- <div id=xmapSearchResultsBck>
403
- <div id=xmapSearchClose onclick=mapCloseSearchWindow()><b>X</b></div>
404
- <div style=padding:5px>Location Results</div>
405
- <div style=width:100%;margin:6px></div>
406
- </div>
407
- <div id=xmapSearchResults style=margin:6px></div>
408
- </div>
409
- </div>
410
- <div id="xmap-info-window"></div>
411
- </div>
412
- <div id=p2 style="display:none">
413
- <div id="p2title"><h1>My Account</h1></div>
414
- <div id="p2info" style="overflow-y:auto">
415
- <div id="p2AccountImageFrame">
416
- <img id="p2AccountImage" alt="" loading="lazy" width="128" height="128" onclick="account_manageImage(0)" src="images/user-256.png" />
417
- <div><a onclick="account_manageImage(0)">Change image</a></div>
418
- </div>
419
- <div id="p2AccountSecurity" style="display:none">
420
- <p><strong>Account security</strong></p>
421
- <div style="margin-left:25px">
422
- <div id="managePhoneNumber1"><div class="p2AccountActions"><span id="authPhoneNumberCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_managePhone()">Manage phone number</a><br /></span></div>
423
- <div id="manageEmail2FA"><div class="p2AccountActions"><span id="authEmailSetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageAuthEmail()">Manage email authentication</a><br /></span></div>
424
- <div id="manageAuthApp"><div class="p2AccountActions"><span id="authAppSetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageAuthApp()">Manage authenticator app</a><br /></span></div>
425
- <div id="manageHardwareOtp"><div class="p2AccountActions"><span id="authKeySetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageHardwareOtp(0)">Manage security keys</a><br /></span></div>
426
- <div id="managePushAuthDev"><div class="p2AccountActions"><span id="authPushAuthDevCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_managePushAuthDev()">Manage push authentication</a><br /></span></div>
427
- <div id="manageMessaging1"><div class="p2AccountActions"><span id="authMessagingCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageMessaging()">Manage messaging</a><br /></span></div>
428
- <div id="manageOtp"><div class="p2AccountActions"><span id="authCodesSetupCheck"><strong>✓</strong></span></div><span><a href=# onclick="return account_manageOtp(0)">Manage backup codes</a><br /></span></div>
429
- <div class="p2AccountActions"></div><span><a href=# onclick="return account_viewPreviousLogins()">View previous logins</a><br /></span>
430
- </div>
431
- </div>
432
- <div id="p2AccountActions">
433
- <p><strong>Account actions</strong></p>
434
- <p class="mL">
435
- <span id="managePhoneNumber2" style="display:none"><a href=# onclick="return account_managePhone()">Manage phone number</a><br /></span>
436
- <span id="manageMessaging2" style="display:none"><a href=# onclick="return account_manageMessaging()">Manage messaging</a><br /></span>
437
- <span id="verifyEmailId" style="display:none"><a href=# onclick="return account_showVerifyEmail()">Verify email</a><br /></span>
438
- <span id="accountEnableNotificationsSpan" style="display:none"><a href=# onclick="return account_enableNotifications()">Enable web notifications</a><br /></span>
439
- <a href=# onclick="return account_showLocalizationSettings()">Localization Settings</a><br />
440
- <a href=# onclick="return account_showAccountNotifySettings()">Notification Settings</a><br />
441
- <span id="p2AccountPassActions">
442
- <span id="accountChangeEmailAddressSpan" style="display:none"><a href=# onclick="return account_showChangeEmail()">Change email address</a><br /></span>
443
- <a href=# onclick="return account_showChangePassword()">Change password</a><span id="p2nextPasswordUpdateTime"></span><br />
444
- <a href=# onclick="return account_showDeleteAccount()">Delete account</a><br />
445
- </span>
446
- <span id="accountCreateLoginTokenSpan" style="display:none"><a href=# onclick="return account_createLoginToken()">Create login token</a><br /></span>
447
- </p>
448
- <br style=clear:both />
449
- </div>
450
- <div id=p2logintokens></div>
451
- <strong>Device Groups</strong>
452
- <span id="p2createMeshLink1"> - <a href=# onclick="return account_createMesh()" class="newMeshBtn"> New</a></span>
453
- <br /><br />
454
- <div id=p2meshes></div>
455
- <div id=p2noMeshFound style="display:none">No device groups.<span id="p2createMeshLink2"> <a href=# onclick="return account_createMesh()"><strong>Get started here!</strong></a></span></div>
456
- <br style=clear:both />
457
- </div>
458
- </div>
459
- <div id=p3 style="display:none">
460
- <div id="p3title"><h1>My Events</h1></div>
461
- <table class="pTable">
462
- <tr>
463
- <td class="h1"></td>
464
- <td class="auto-style1">
465
- <input type="button" style="display:none" value="Download Report" onclick=p3showReportDialog() />
466
- </td>
467
- <td class="auto-style1">
468
- Show
469
- <select id=p3limitdropdown onchange=refreshEvents()>
470
- <option value=60>Last 60</option>
471
- <option value=120>Last 120</option>
472
- <option value=250>Last 250</option>
473
- <option value=500>Last 500</option>
474
- <option value=1000>Last 1000</option>
475
- <option value="">No limit</option>
476
- </select>
477
- <a href=# onclick=p3showDownloadEventsDialog(2)><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
478
- </td>
479
- <td class="h2"></td>
480
- </tr>
481
- </table>
482
- <div id=p3events></div>
483
- </div>
484
- <div id=p4 style="display:none">
485
- <div id="p4title"><h1>My Users</h1></div>
486
- <table class="pTable">
487
- <tr>
488
- <td class="h1"></td>
489
- <td class="style14">
490
- <div style="float:right">
491
- <input type=button onclick=showUserBroadcastDialog() style=margin-right:6px value="Broadcast" />
492
- <a href=# onclick=p4downloadUserInfo()><img style="cursor:pointer" title="Download user information" src="images/link4.png" /></a>
493
- <a href=# onclick=p4batchAccountCreate()><img id=p4UserBatchCreate style="cursor:pointer;display:none" title="Batch create many user accounts" src="images/link6.png" /></a>
494
- <img style="cursor:pointer;margin-top:3px;margin-left:6px" id=usersListToolbarSettings src="images/icon-gear.png" loading=lazy width=16 height=16 onclick="onUsersViewSettings()" />
495
- </div>
496
- <div>
497
- <input type=button id=UsersSelectAllButton onclick="p3usersSelectallButtonFunction()" value="Select All" />
498
- <input type=button id=UsersGroupActionButton disabled="disabled" value="Group Action" onclick=p3usersGroupActionFunction() />
499
- <input id=UserNewAccountButton type=button onclick=showCreateNewAccountDialog() value="New Account..." />
500
- <input id=UserSearchInput type=search style=width:120px;margin-left:6px placeholder=Filter onchange=onUserSearchInputChanged() onkeyup=onUserSearchInputChanged() autocomplete=off onfocus=onUserSearchFocus(1) onblur=onUserSearchFocus(0) />
501
- </div>
502
- </td>
503
- <td class="h2"></td>
504
- </tr>
505
- </table>
506
- <div id="p3users"></div>
507
- </div>
508
- <div id=p5 style="display:none">
509
- <div id="p5title"><h1>My Files</h1></div>
510
- <table id="p5toolbar" cellpadding="0" cellspacing="0">
511
- <tr>
512
- <td id="p5filehead" valign=bottom>
513
- <div id="p5rightOfButtons"></div>
514
- <div>
515
- <input type=button id=p5FolderUp disabled="disabled" onclick="return p5folderup();" value="Up" />
516
- <input type=button id=p5SelectAllButton disabled="disabled" onclick="p5selectallfile();" value="Select All" />
517
- <input type=button id=p5RenameFileButton disabled="disabled" value="Rename" onclick="p5renamefile();" />
518
- <input type=button id=p5DeleteFileButton disabled="disabled" value="Delete" onclick="p5deletefile();" />
519
- <input type=button id=p5ViewFileButton disabled="disabled" value="Edit" onclick="p5viewfile()" />
520
- <input type=button id=p5NewFolderButton disabled="disabled" value="New Folder" onclick="p5createfolder();" />
521
- <input type=button id=p5UploadButton disabled="disabled" value="Upload" onclick="p5uploadFile()" />
522
- <input type=button id=p5CutButton disabled="disabled" value="Cut" onclick="p5copyFile(1)" />
523
- <input type=button id=p5CopyButton disabled="disabled" value="Copy" onclick="p5copyFile(0)" />
524
- <input type=button id=p5PasteButton disabled="disabled" value="Paste" onclick="p5pasteFile()" />
525
- </div>
526
- </td>
527
- </tr>
528
- <tr>
529
- <td id="p5filesubhead">
530
- <div style=float:right>
531
- <select id=p5sortdropdown onchange=updateFiles()>
532
- <option value="1" selected="selected">Sort by name</option>
533
- <option value="2">Sort by size</option>
534
- <option value="3">Sort by date</option>
535
- <option value="4">Descend by name</option>
536
- <option value="5">Descend by size</option>
537
- <option value="6">Descend by date</option>
538
- </select>
539
- </div>
540
- <div> <span id="p5currentpath"></span></div>
541
- </td>
542
- </tr>
543
- </table>
544
- <div id="p5filetable">
545
- <!--
546
- <form id=p5fileCatchAll method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame>
547
- <input type=file id=p5fileCatchAllInput name=files style="position:absolute;left:0;width:100%;top:0;bottom:0;opacity:0;display:none" onchange="p5fileCatchAllInputChanged(event)" />
548
- <input id=p5fileDragLink2 name="link" style="display:none" />
549
- <input type=submit id=p5fileCatchAllSubmit style="display:none" />
550
- </form>
551
- -->
552
- <div id="p5PublicShare" style=""><div>These files are shared publicly, click "link" to get public url.</div></div>
553
- <div id="bigok" style="display:none"><b>✓</b></div>
554
- <div id="bigfail" style="display:none"><b>✗</b></div>
555
- <span id="p5files"></span>
556
- </div>
557
- <table id="p5toolbarBottom" style=width:100% cellpadding=0 cellspacing=0>
558
- <tr><td class=style6> <span id="p5bottomstatus"></span></td></tr>
559
- </table>
560
- </div>
561
- <div id=p6 style="display:none">
562
- <div id="p6info" style="overflow-y:auto">
563
- <div id="p6title">
564
- <img id=MainMeshImage src="serverpic.ashx">
565
- <h1>My Server</h1>
566
- </div>
567
- <div id="p2ServerActions">
568
- <p><strong>Server actions</strong></p>
569
- <div style="margin-left:25px">
570
- <div id="p2ServerActionsBackup"><div class="p2AccountActions"><span style="display:none"><strong>✓</strong></span></div><a id="p6backuplink" href="{{{domainurl}}}backup.zip" rel="noreferrer noopener" target="_blank">Download server backup</a></div>
571
- <div id="p2ServerActionsRestore"><div class="p2AccountActions"><span style="display:none"><strong>✓</strong></span></div><a href=# onclick="return server_showRestoreDlg()">Restore server with backup</a></div>
572
- <div id="p2ServerActionsGoogleBackup" style="display:none"><div class="p2AccountActions"><span id="p2ServerActionsGoogleBackupCheck" style="display:none"><strong>✓</strong></span></div><span><a href=# onclick="return server_setupGoogleDriveBackup()">Google Drive backup</a><br /></span></div>
573
- <div id="p2ServerActionsVersion"><div class="p2AccountActions"><span style="display:none"><strong>✓</strong></span></div><a href=# onclick="return server_showVersionDlg()">Check server version</a></div>
574
- <div id="p2ServerActionsErrors"><div class="p2AccountActions"><span style="display:none"><strong>✓</strong></span></div><a href=# onclick="return server_showErrorsDlg()">Show server error log</a></div>
575
- </div>
576
- <br />
577
- </div>
578
- <strong>Server Statistics</strong><br /><br />
579
- <div id="serverStats">
580
- <div id="serverCpuChartView" style="display:none">
581
- <div class="chartViewCanvas"><canvas id="serverCpuChart"></canvas></div>
582
- <div class="chartViewText" id="serverCpuChartText"></div>
583
- </div>
584
- <div id="serverMemoryChartView" style="display:none">
585
- <div class="chartViewCanvas"><canvas id="serverMemoryChart"></canvas></div>
586
- <div class="chartViewText" id="serverMemoryChartText"></div>
587
- </div><br /><br />
588
- <div id="serverStatsTable"></div>
589
- </div>
590
- <div id="serverWarningsDiv" style="display:none">
591
- <br /><strong>Server Warnings</strong><br /><br />
592
- <div id="serverCertWarnings"></div>
593
- <div id="serverWarnings"></div>
594
- </div>
595
- </div>
596
- </div>
597
- <div id=p10 style="display:none">
598
- <div id=p10title>
599
- <div id="p10BackButton"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
600
- <h1>General - <span id=p10deviceName></span></h1>
601
- </div>
602
- <div id=p10info style="overflow-y:auto">
603
- <table style="width:100%" cellpadding="0" cellspacing="0">
604
- <tr>
605
- <td style=width:auto valign=top>
606
- <div id=p10html></div>
607
- </td>
608
- <td style=width:20px></td>
609
- <td style=width:200px;vertical-align:top;position:relative valign=top>
610
- <div class="deviceNotifyLargeDot">
611
- <div id="p10deviceMsg" onclick=showDeviceMessages(null,null,event) class=deviceNotifyDotSub></div>
612
- <img id="p10deviceStar" class=deviceNotifyDotSub src=images/icon-star-notify-16.png width=16 height=16>
613
- <img id="p10deviceNotify" onclick=showDeviceSessions(null,null,event) class=deviceNotifyDotSub src=images/icon-relay-notify.png width=16 height=16>
614
- <img id="p10deviceHelp" onclick=showDeviceHelpRequests(null,null,event) class=deviceNotifyDotSub src=images/icon-help-notify-16.png width=16 height=16>
615
- </div>
616
- <div id="p10deviceBattery" class="deviceBatteryLarge deviceBatteryLarge1"></div>
617
- <a href=# onclick=p10showiconselector()><img id=MainComputerImage></a>
618
- <div id=MainComputerState></div>
619
- </td>
620
- </tr>
621
- </table><br />
622
- <div id=p10html2></div>
623
- <div id=p10html3></div>
624
- <div id=p10html4></div>
625
- <div id=p10html5></div>
626
- </div>
627
- </div>
628
- <div id=p11 class="noselect" style="display:none">
629
- <div id="p11title">
630
- <div id=p11deviceNameHeader>
631
- <div id="p11BackButton"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
632
- <div id="devListToolbarViewIcons"><div class="viewSelector" onclick=deskToggleFull(event) title="Full Screen. Hold shift to browser full screen."><div class="viewSelector5"></div></div></div>
633
- <h1>Desktop - <span id=p11deviceName></span></h1>
634
- </div>
635
- </div>
636
- <div id="p11warning" onclick="showFeaturesDlg()">
637
- <div class="icon2"></div>
638
- <div class="warningbox">Redirection port or KVM feature is disabled<span id="p11warninga">, click here to enable it.</span></div>
639
- </div>
640
- <div id="p11warning2" onclick="showPowerActionDlg()">
641
- <div class="icon2"></div>
642
- <div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
643
- </div>
644
- <div style="position:absolute;right:16px;margin-top:-14px;font-size:x-small;color:black">
645
- <div id="p11capslock" style="display:inline-block;margin-left:1px;border-radius:5px;background-color:#A3FFB8;padding:2px">
646
- CAPS
647
- </div>
648
- <div id="p11scrolllock" style="display:inline-block;margin-left:1px;border-radius:5px;background-color:#A3FFB8;padding:2px">
649
- SCROLL
650
- </div>
651
- <div id="p11numlock" style="display:inline-block;margin-left:1px;border-radius:5px;background-color:#A3FFB8;padding:2px">
652
- NUM
653
- </div>
654
- </div>
655
- <div id=deskarea0 cellpadding=0 cellspacing=0>
656
- <div id=deskarea1 class="areaHead">
657
- <div class="toright2">
658
- <div id="idx_deskFullBtn2" onclick=deskToggleFull(event) style="float:right"> ✖</div>
659
- <span id="p11power"></span>
660
- <div class='deskareaicon' title="Toggle View Mode" onclick="toggleAspectRatio(1)">⇲</div>
661
- <div class='deskareaicon' title="Rotate Left" onclick="drotate(-1)">↺</div>
662
- <div class='deskareaicon' title="Rotate Right" onclick="drotate(1)">↻</div>
663
- <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>
664
- <input id="deskFocusBtn" type="button" title="Toggle focus mode, when active only the region around the mouse is updated" onkeypress="return false" onkeydown="return false" value="Focus All" onclick="deskToggleFocus()" style="margin-right:3px;display:none" />
665
- <input id="deskActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() class="mR" />
666
- <input id="deskActionsSettings" type="button" value="Settings..." title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" class="mR" />
667
- <input type="button" title="Change the power state of the remote machine" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="display:none" />
668
- <div id="desktopCustomUiButtons" style="float:left"></div>
669
- </div>
670
- <div>
671
- <input type="button" id="autoconnectbutton1" value="AutoConnect" onclick=autoConnectDesktop(event) onkeypress="return false" onkeydown="return false" style="display:none;margin-right:4px" />
672
- <span id=connectbutton1span><input type=button id=connectbutton1 cmenu="deskConnectButton" title="Connect using MeshAgent remote desktop" value="Connect" onclick=connectDesktop(event,3) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
673
- <span id=connectbutton1rspan><input type=button id=connectbutton1r cmenu="altPortContextMenu" value="RDP Connect" title="Connect using RDP" onclick=askRdpCredentials() onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
674
- <span id=connectbutton1hspan><input type=button id=connectbutton1h value="HW Connect" title="Connect using hardware KVM" onclick=connectDesktop(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span>
675
- <span id=disconnectbutton1span><input type=button id=disconnectbutton1 cmenu="deskDisconnectButton" value="Disconnect" onclick=connectDesktop(event,0) onkeypress="return false" onkeydown="return false" /></span>
676
- <span id="deskstatus" style="line-height:22px">Disconnected</span><span id="deskmetadata"></span>
677
- </div>
678
- </div>
679
- <div id=deskarea3x>
680
- <div id="p11bigok" style="display:none"><b>✓</b></div>
681
- <div id="p11bigfail" style="display:none"><b>✗</b></div>
682
- <div id=DeskFocus oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></div>
683
- <div id=DeskParent>
684
- <canvas id=Desk width=640 height=480 oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event) onmousewheel=dmousewheel(event)></canvas>
685
- </div>
686
- <div id=DeskTools>
687
- <div id=deskToolsAreaTop>
688
- <a id=DeskToolsRefreshButton style="right:2px" onclick="refreshDeskTools()">Refresh</a>
689
- <div id=deskToolsTopTabProcess class="deskToolsTopTab" onclick="changeDeskToolTab(0)" style="left:0px;bottom:0px">Processes</div>
690
- <div id=deskToolsTopTabService class="deskToolsTopTab" onclick="changeDeskToolTab(1)" style="display:none;left:90px;color:gray">Services</div>
691
- </div>
692
- <div id=deskToolsArea>
693
- <div id="DeskToolsProcessTab">
694
- <div id=deskToolsHeader>
695
- <a class="colmn1" title="Sort by process id" onclick=sortProcess(0)>PID</a>
696
- <a class="colmn2" title="Sort by name" onclick=sortProcess(1)>Name</a>
697
- </div>
698
- <div id="DeskToolsProcesses" style=""></div>
699
- </div>
700
- <div id="DeskToolsServiceTab" style="display:none">
701
- <div id=deskToolsServiceHeader>
702
- <a class="colmn1" style="width:70px" title="Sort by state" onclick=sortService(0)>State</a>
703
- <a class="colmn2" title="Sort by name" onclick=sortService(1)>Name</a>
704
- </div>
705
- <div id="DeskToolsServices" style=""></div>
706
- </div>
707
- </div>
708
- </div>
709
- <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;text-align:left" onclick=p11clearConsoleMsg()></div>
710
- <div id=p11DeskSessionSelector style="display:none;position:absolute;left:30px;top:17px;right:30px;bottom:17px;overflow-y:auto"></div>
711
- </div>
712
- <div id=deskarea4 class="areaFoot">
713
- <div class="toright2">
714
- <span id="DeskLatency" title="Desktop Session Latency"></span>
715
- <span id="DeskTimer" style="line-height:22px" title="Session time"></span>
716
- <input id=DeskToolsButton type=button value=Tools title="Toggle tools view" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()" />
717
- <span> </span>
718
- <span id=DeskRunButton cmenu="deskPreConfigScriptContextMenu" class="deskarea" title="Run a script on this computer"><img class="desktopButtons" src='images/icon-play.png' onclick=runDeviceCmd() height=16 width=16 style=padding-top:2px /></span>
719
- <span id=DeskChatButton class="deskarea" title="Open chat window to this computer"><img class="desktopButtons" src='images/icon-chat.png' onclick=deviceChat(event) height=16 width=16 style=padding-top:2px /></span>
720
- <span id=DeskNotifyButton title="Display a notification on the remote computer"><img class="desktopButtons" src='images/icon-notify.png' onclick=deviceToastFunction() height=16 width=16 style=padding-top:2px /></span>
721
- <span id=DeskLockButton title="Lock the remote computer"><img src='images/icon-lock.png' class="desktopButtons" onclick=deviceLockFunction() height=16 width=16 /></span>
722
- <span id=DeskOpenWebButton title="Open a web address on the remote computer"><img class="desktopButtons" src='images/icon-url2.png' onclick=deviceUrlFunction() height=16 width=16 /></span>
723
- <span id=DeskBackgroundButton title="Toggle remote desktop background"><img class="desktopButtons" src='images/icon-background.png' onclick=deviceToggleBackground(event) height=16 width=16 /></span>
724
- <span id=DeskSaveImageButton title="Save a screenshot of the remote desktop"><img class="desktopButtons" src='images/icon-camera.png' onclick=deskSaveImage() height=16 width=16 /></span>
725
- <span id=DeskRecordButton cmenu=deskPlayerContextMenu title="Record remote desktop session to file" style="display:none"><img class="desktopButtons" id=DeskRecordButtonImage src='images/icon-film.png' onclick=deskRecordSession() height=16 width=16 /></span>
726
- <span id=DeskClipboardInButton title="Download remote clipboard to local clipboard" style="display:none"><img class="desktopButtons" id=DeskClipboardInButtonImage src='images/icon-clipboard-in.png' onclick=deskClipboardInFunction() height=16 width=16 /></span>
727
- <span id=DeskClipboardOutButton title="Upload local clipboard to remote device"><img class="desktopButtons" id=DeskClipboardOutButtonImage src='images/icon-clipboard-out.png' onclick=deskClipboardOutFunction() height=16 width=16 /></span>
728
- <span id=DeskRefreshButton title="Refresh the desktop"><img class="desktopButtons" id=DeskRefreshButtonImage src='images/icon-refresh.png' onclick=deskRefreshFunction() height=16 width=16 /></span>
729
- <span id=DeskInputLockedButton title="Remote input is locked"><img class="desktopButtons" id=DeskInputLockedButtonImage src='images/icon-keylock-red.png' onclick=deskInputLockFunction(0) height=16 width=16 /></span>
730
- <span id=DeskInputUnLockedButton title="Remote input is unlocked"><img class="desktopButtons" id=DeskInputUnLockedButtonImage src='images/icon-keylock.png' onclick=deskInputLockFunction(1) height=16 width=16 /></span>
731
- <span id=DeskGuestShareButton title="Share the device with a guest"><img class="desktopButtons" id=DeskInputUnLockedButtonImage src='images/icon-share2.png' onclick=showShareDevice() height=16 width=16 /></span>
732
- </div>
733
- <div class="toright2"><span id=DeskMonitorSelectionSpan></span></div>
734
- <div>
735
- <select id="deskkeys" cmenu=deskKeyShortcutContextMenu></select>
736
- <input id="DeskWD" type=button value="Send" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()" />
737
- <input id="DeskESC" style="display:none" type="button" value="ESC" onkeypress="return false" onkeydown="return false" onclick="sendDeskEsc()" />
738
- <input id="DeskClip" type="button" value="Clipboard" onkeypress="return false" onkeydown="return false" onclick="showDeskClip()" />
739
- <input id="DeskType" cmenu="deskPreConfigShortcutContextMenu" type="button" value="Type" onkeypress="return false" onkeydown="return false" onclick="showDeskType()" />
740
- <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>
741
- </div>
742
- </div>
743
- </div>
744
- </div>
745
- <div id=p12 style="display:none">
746
- <div id="p12title">
747
- <div id="p12BackButton"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
748
- <div id="devListToolbarViewIcons2" style="float:right"><div class="viewSelector" onclick=deskToggleFull(event) title="Full Screen. Hold shift to browser full screen."><div class="viewSelector5"></div></div></div>
749
- <h1>Terminal - <span id=p12deviceName></span></h1>
750
- </div>
751
- <div id="p12warning" onclick=showFeaturesDlg()>
752
- <div class="icon2"></div>
753
- <div class="warningbox">Redirection port or KVM feature is disabled<span id="p12warninga">, click here to enable it.</span></div>
754
- </div>
755
- <div id="p12warning2" onclick=showPowerActionDlg()>
756
- <div class="icon2"></div>
757
- <div class="warningbox">Remote computer is not powered on, click here to issue a power command.</div>
758
- </div>
759
- <div id=termTable style="position:relative">
760
- <table style="width:100%" cellpadding=0 cellspacing=0>
761
- <tr>
762
- <td class="areaHead" style="line-height:22px">
763
- <div class="toright2">
764
- <div id="idx_termFullBtn2" onclick=deskToggleFull(event) style="float:right"> ✖</div>
765
- <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>
766
- <input id="termActionsBtn" type=button title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() />
767
- <div id="terminalCustomUpperRight" style="float:left;margin-right:6px"></div>
768
- <div id="terminalCustomUiButtons" style="float:left"></div>
769
- </div>
770
- <div>
771
- <input type="button" id="autoconnectbutton2" value="AutoConnect" onclick=autoConnectTerminal(event) onkeypress="return false" onkeydown="return false" style="display:none" /><span id="connectbutton2span" style="margin-right:4px"><input type="button" id="connectbutton2" cmenu="termConnectButton" value="Connect" onclick=connectTerminal(event,1) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span><span id="connectbutton2sspan" style="margin-right:4px"><input type="button" id="connectbutton2s" cmenu=sshPortContextMenu value="SSH Connect" onclick=connectTerminal(event,3) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span><span id="connectbutton2hspan" style="margin-right:4px"><input type="button" id="connectbutton2h" value="HW Connect" title="Connect using Intel® AMT hardware KVM" onclick=connectTerminal(event,2) onkeypress="return false" onkeydown="return false" disabled="disabled" /></span><span id="disconnectbutton2span" style="margin-right:4px"><input type="button" id="disconnectbutton2" value="Disconnect" onclick=connectTerminal(event,0) onkeypress="return false" onkeydown="return false" /></span>
772
- <span id="termstatus" style="line-height:22px">Disconnected</span><span id="termtitle"></span>
773
- </div>
774
- </td>
775
- </tr>
776
- <tr>
777
- <td id="termarea3x">
778
- <div id="termarea3xdiv" style="width:100%;height:100%;text-align:left"></div>
779
- <pre id="Term"></pre>
780
- </td>
781
- </tr>
782
- <tr>
783
- <td class="areaFoot">
784
- <div class="toright2">
785
- <span id="TermTimer" title="Session time"></span>
786
- <span id="terminalSettingsButtons" style="display:none">
787
- <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()" />
788
- <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()" />
789
- <input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()" />
790
- </span>
791
- <span id="terminalSizeDropDown" style="display:none">
792
- <select id="termSizeList" onkeypress="return false"><option value="1">80x25</option><option value="2">100x30</option></select>
793
- </span>
794
- <span id="specialKeyDropDown">
795
- <select id="specialkeylist" onkeypress="return false"></select>
796
- <input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />
797
- </span>
798
- </div>
799
- <div>
800
-
801
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlcbutton" value="Ctl-C" onclick="termSendKey(3,'ctrlcbutton')" />
802
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="ctrlxbutton" value="Ctl-X" onclick="termSendKey(24,'ctrlxbutton')" />
803
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="escbutton" value="ESC" onclick="termSendKey(27,'escbutton')" />
804
- <input type=button onkeypress="return false" onkeydown="return false" class="bottombutton" id="bsbutton" value="Backspace" onclick="termSendKey(8,'bsbutton')" style="display:none" />
805
- <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" />
806
- </div>
807
- </td>
808
- </tr>
809
- </table>
810
- <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>
811
- </div>
812
- </div>
813
- <div id=p13 style="display:none">
814
- <div id="p13title">
815
- <div id="p13BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
816
- <h1>Files - <span id=p13deviceName></span></h1>
817
- </div>
818
- <table id="p13toolbar" cellpadding="0" cellspacing="0">
819
- <tr>
820
- <td class="areaHead" style="line-height:22px">
821
- <div class="toright2">
822
- <input id="filesActionsBtn" type=button title="Perform power actions on the device" value=Actions onclick=deviceActionFunction() />
823
- <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>
824
- <div id="filesCustomUpperRight" style="float:left;margin-right:6px"></div>
825
- <div id="filesCustomUiButtons" style="float:left"></div>
826
- </div>
827
- <div>
828
- <input id=p13AutoConnect value="AutoConnect" onclick=autoConnectFiles(event) type="button" style="display:none" />
829
- <input id=p13Connect value="Connect" cmenu="filesConnectButton" onclick=connectFiles(event,1) type="button" />
830
- <input id=p13Connects value="SFTP Connect" cmenu=sshPortContextMenu onclick=connectFiles(event,2) type="button" />
831
- <input id=p13Disconnect value="Disconnect" onclick=connectFiles(event) type="button" />
832
- <span id=p13Status>Disconnected</span>
833
- </div>
834
- </td>
835
- </tr>
836
- <tr>
837
- <td class="areaHead2" valign=bottom>
838
- <div id="p13rightOfButtons" class="toright2"></div>
839
- <div>
840
- <input type=button style="margin-right:2px" disabled="disabled" id=p13FolderUp value="Up" onclick="p13folderup()" />
841
- <input type=button style="margin-right:2px" disabled="disabled" id=p13SelectAllButton value="Select All" onclick="p13selectallfile()" />
842
- <input type=button style="margin-right:2px" disabled="disabled" id=p13RenameFileButton value="Rename" onclick="p13renamefile()" />
843
- <input type=button style="margin-right:2px" disabled="disabled" id=p13DeleteFileButton value="Delete" onclick="p13deletefile()" />
844
- <input type=button style="margin-right:2px" disabled="disabled" id=p13ViewFileButton value="Edit" onclick="p13viewfile()" />
845
- <input type=button style="margin-right:2px" disabled="disabled" id=p13NewFolderButton value="New Folder" onclick="p13createfolder()" />
846
- <input type=button style="margin-right:2px" disabled="disabled" id=p13UploadButton value="Upload" onclick="p13uploadFile()" />
847
- <input type=button style="margin-right:2px" disabled="disabled" id=p13CutButton value="Cut" onclick="p13copyFile(1)" />
848
- <input type=button style="margin-right:2px" disabled="disabled" id=p13CopyButton value="Copy" onclick="p13copyFile(0)" />
849
- <input type=button style="margin-right:2px" disabled="disabled" id=p13PasteButton value="Paste" onclick="p13pasteFile()" />
850
- <input type=button style="margin-right:2px" disabled="disabled" id=p13ZipButton value="Zip" onclick="p13zipFiles()" />
851
- <input type=button style="margin-right:2px" disabled="disabled" id=p13RefreshButton value="Refresh" onclick="p13folderup(9999)" />
852
- <input type=button style="margin-right:2px" disabled="disabled" id=p13FindButton value="Find" onclick="p13findfile()" />
853
- </div>
854
- </td>
855
- </tr>
856
- <tr>
857
- <td class="areaHead3">
858
- <div class="toright2">
859
- <select id=p13sortdropdown onchange=p13updateFiles()>
860
- <option value=1 selected="selected">Sort by name</option>
861
- <option value=2>Sort by size</option>
862
- <option value=3>Sort by date</option>
863
- <option value=4>Descend by name</option>
864
- <option value=5>Descend by size</option>
865
- <option value=6>Descend by date</option>
866
- </select>
867
- </div>
868
- <div> <span id="p13currentpath"></span></div>
869
- </td>
870
- </tr>
871
- </table>
872
- <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>
873
- <div id="p13filetable" style="">
874
- <div id="p13bigok" style="display:none"><b>✓</b></div>
875
- <div id="p13bigfail" style="display:none"><b>✗</b></div>
876
- <span id="p13files"></span>
877
- </div>
878
- <table id="p13toolbarBottom" cellpadding=0 cellspacing=0>
879
- <tr><td class=style6> <span id="p13bottomstatus"></span></td></tr>
880
- </table>
881
- </div>
882
- <div id=p14 style="display:none">
883
- <div id="p14title">
884
- <div id="p14BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
885
- <div id="devListToolbarViewIcons"><div class="viewSelector" onclick=deskToggleFull(event) title="Full Screen. Hold shift to browser full screen."><div class="viewSelector5"></div></div></div>
886
- <h1><span id=p14deviceNamePrefix>Intel® AMT</span> - <span id=p14deviceName></span></h1>
887
- </div>
888
- <iframe id=p14iframe src="{{{domainurl}}}commander.ashx"></iframe>
889
- </div>
890
- <div id=p15 style="display:none">
891
- <div id="p15title">
892
- <div id="p15BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
893
- <h1><span id=p15deviceName></span></h1>
894
- </div>
895
- <table id="consoleTable" cellpadding=0 cellspacing=0>
896
- <tr>
897
- <td class="areaHead">
898
- <div class="toright2">
899
- <div id=p15coreName title="Information about current core running on this agent"></div>
900
- <input type=button id=p15uploadCore value="Agent Action" onclick=p15uploadCore(event) title="Change the agent Java Script code module" />
901
- <img onclick=p15downloadConsoleText() style="cursor:pointer;margin-top:6px" title="Download console text" src="images/link4.png" />
902
- </div>
903
- <div id="p15statetext"></div>
904
- </td>
905
- </tr>
906
- <tr>
907
- <td>
908
- <div class="areaProgress"><div id="consoleprogressbar" style=""></div></div>
909
- </td>
910
- </tr>
911
- <tr>
912
- <td id=p15agentConsole>
913
- <pre id=p15agentConsoleText></pre>
914
- </td>
915
- </tr>
916
- <tr>
917
- <td class="areaFoot">
918
- <table style="width:100%">
919
- <tr>
920
- <td style="width:99%">
921
- <input id=p15consoleText style=width:100% onkeyup=p15consoleSend(event) onfocus=onConsoleFocus(1) onblur=onConsoleFocus(0) />
922
- </td>
923
- <td> </td>
924
- <td id="p15outputselecttd">
925
- <select id=p15outputselect onchange="setupConsole()">
926
- <option id="p15outputselect1" value=1>Agent</option>
927
- <option id="p15outputselect3" value=3>Push</option>
928
- <option id="p15outputselect2" value=2>MQTT</option>
929
- </select>
930
- </td>
931
- <td style="width:1%"><input id="id_p15consoleClear" type="button" class="bottombutton" value="Clear" onclick="p15consoleClear()" /></td>
932
- </tr>
933
- </table>
934
- </td>
935
- </tr>
936
- </table>
937
- </div>
938
- <div id=p16 style="display:none">
939
- <div id="p16title">
940
- <div id="p16BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
941
- <h1>Events - <span id=p16deviceName></span></h1>
942
- </div>
943
- <table class="pTable">
944
- <tr>
945
- <td class="h1"></td>
946
- <!--<td> <input type=button onclick=refreshDeviceEvents() value="Refresh" /></td>-->
947
- <td class="auto-style1">
948
- Show
949
- <select id=p16limitdropdown onchange=refreshDeviceEvents()>
950
- <option value=60>Last 60</option>
951
- <option value=120>Last 120</option>
952
- <option value=250>Last 250</option>
953
- <option value=500>Last 500</option>
954
- <option value=1000>Last 1000</option>
955
- </select>
956
- <a href=# onclick=p3showDownloadEventsDialog(1)><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
957
- </td>
958
- <td class="h2"></td>
959
- </tr>
960
- </table>
961
- <div id=p16events></div>
962
- </div>
963
- <div id=p17 style="display:none;margin-left:-18px">
964
- <div id="p17title" style="margin-left:18px">
965
- <div id="p17BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
966
- <div id="devListToolbarViewIcons3"><div class="viewSelector" onclick=deskToggleCpuGraph(event) title="Show device CPU and memory usage."><div class="viewSelector6"></div></div></div>
967
- <h1>Details - <span id=p17deviceName></span></h1>
968
- </div>
969
- <div id=p17info style="overflow-y:auto">
970
- <div id=p17graph style="width:100%">
971
- <table style=width:100%>
972
- <tr>
973
- <td style=width:64px;vertical-align:top>
974
- <img src=images/details/graph64.png border=0 width=64 />
975
- </td>
976
- <td>
977
- <div class=DevSt style=margin-bottom:3px;margin-left:16px><b>Live Graph</b></div>
978
- <div style="margin-bottom:10px;margin-left:16px;height:240px;width:calc(100% - 16px);position:relative">
979
- <canvas id=deviceDetailsStats style="position:absolute;top:0;left:0;right:0;bottom:0"></canvas>
980
- </div>
981
- <div id="extraGraphValues" style="display:none;margin-left:30px;margin-bottom:15px"></div>
982
- </td>
983
- </tr>
984
- </table>
985
- </div>
986
- <div id=p17info2></div>
987
- </div>
988
- </div>
989
- <div id=p19 style="display:none">
990
- <div id="p19title">
991
- <div id="p19BackButton" style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
992
- <h1>Plugins - <span id=p19deviceName></span></h1>
993
- </div>
994
- <div id="p19headers"></div>
995
- <div id=p19pages></div>
996
- </div>
997
- <div id=p20 style="display:none">
998
- <div id=p20main style="overflow-y:auto">
999
- <div id="p20title">
1000
- <picture id=MainMeshImage style=border-width:0px;height:200px;width:200px;float:right>
1001
- <source type="image/webp" width=200 height=200 srcset="images/webp/mesh-256.webp" />
1002
- <img alt="" width=200 height=200 src=images/mesh-256.png />
1003
- </picture>
1004
- <div style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
1005
- <h1>General - <span id=p20meshName></span></h1>
1006
- </div>
1007
- <p id=p20info></p>
1008
- <p id=p20info2></p>
1009
- </div>
1010
- </div>
1011
- <div id=p21 style="display:none">
1012
- <div id="p21title">
1013
- <div style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
1014
- <h1>Summary - <span id=p21meshName></span></h1>
1015
- </div>
1016
- <div id=p21main style="overflow-y:auto">
1017
- <div style="width:100%">
1018
- <div style="display:table;width:93%">
1019
- <div id="meshPowerChartDiv" style="width:23%;display:inline-block;text-align:center;max-width:250px">
1020
- <div style="margin:10px;font-size:16px">Power States</div>
1021
- <canvas id="meshPowerChart" style="width:250px;height:250px"></canvas>
1022
- </div>
1023
- <div id="meshOsChartDiv" style="width:23%;display:inline-block;text-align:center;max-width:250px">
1024
- <div style="margin:10px;font-size:16px">Agent Types</div>
1025
- <canvas id="meshOsChart" style="width:250px;height:250px"></canvas>
1026
- </div>
1027
- <div id="meshConnChartDiv" style="width:23%;display:inline-block;text-align:center;max-width:250px">
1028
- <div style="margin:10px;font-size:16px">Connectivity</div>
1029
- <canvas id="meshConnChart" style="width:250px;height:250px"></canvas>
1030
- </div>
1031
- <div id="meshSecurityChartDiv" style="width:23%;display:inline-block;text-align:center;max-width:250px">
1032
- <div style="margin:10px;font-size:16px">Security</div>
1033
- <canvas id="meshSecurityChart" style="width:250px;height:250px"></canvas>
1034
- </div>
1035
- </div>
1036
- </div>
1037
- <p id=p21info style="overflow-y:auto"></p>
1038
- </div>
1039
- </div>
1040
- <div id=p30 style="display:none">
1041
- <div id="p30title">
1042
- <div style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
1043
- <h1>General - <span id=p30userName></span></h1>
1044
- </div>
1045
- <div id="p30info" style="overflow-y:auto">
1046
- <table style="width:100%" cellpadding="0" cellspacing="0">
1047
- <tr>
1048
- <td style=width:auto valign=top>
1049
- <div id=p30html></div>
1050
- </td>
1051
- <td style=width:20px></td>
1052
- <td style=width:200px;position:relative valign=top>
1053
- <img id="p30userAuthServiceLogo" loading="lazy" style="display:none" class=userAuthStrategyLogo width=64 height=64>
1054
- <picture id=MainUserImage style="display:none;border-width:0px;height:200px;width:200px;float:right" onclick="account_manageImage(1)">
1055
- <source type="image/webp" width=200 height=200 srcset="images/webp/user-256.webp" />
1056
- <img alt="" width=200 height=200 src=images/user-256.png />
1057
- </picture>
1058
- <img id=MainUserImageEx alt="" width=200 height=200 src=images/user-256.png onclick="account_manageImage(1)" />
1059
- <div style="width:100%;text-align:center"><strong><span id=MainUserState></span></strong></div>
1060
- </td>
1061
- </tr>
1062
- </table><br />
1063
- <div id=p30html2></div>
1064
- <div id=p30html3></div>
1065
- </div>
1066
- </div>
1067
- <div id=p31 style="display:none">
1068
- <div id="p31title">
1069
- <div style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
1070
- <h1>Events - <span id=p31userName></span></h1>
1071
- </div>
1072
- <table class="pTable">
1073
- <tr>
1074
- <td class="h1"></td>
1075
- <!--<td> <input type=button onclick=refreshUsersEvents() value="Refresh" /></td>-->
1076
- <td class="auto-style1">
1077
- Show
1078
- <select id=p31limitdropdown onchange=refreshUsersEvents()>
1079
- <option value=60>Last 60</option>
1080
- <option value=120>Last 120</option>
1081
- <option value=250>Last 250</option>
1082
- <option value=500>Last 500</option>
1083
- <option value=1000>Last 1000</option>
1084
- <option value="">No limit</option>
1085
- </select>
1086
- <a href=# onclick=p3showDownloadEventsDialog(3)><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
1087
- </td>
1088
- <td class="h2"></td>
1089
- </tr>
1090
- </table>
1091
- <div id=p31events style=""></div>
1092
- </div>
1093
- <div id=p40 style="display:none">
1094
- <div id="p40title"><h1>My Server Stats</h1></div>
1095
- <div class="areaHead">
1096
- <div class="toright2">
1097
- <select id=p40server style="display:none" onchange=updateServerTimelineStats()>
1098
- </select>
1099
- <select id=p40type onchange=updateServerTimelineStats()>
1100
- <option value=0>Connections</option>
1101
- <option value=1>Memory</option>
1102
- <option value=5>CPU</option>
1103
- <option value=3>Inbound Traffic</option>
1104
- <option value=4>Outbound Traffic</option>
1105
- </select>
1106
- <select id=p40time onchange=updateServerTimelineHours()>
1107
- <option value=3>Last 3 hours</option>
1108
- <option value=8>Last 8 hours</option>
1109
- <option value=24>Last day</option>
1110
- <option value=168>Last week</option>
1111
- <option value=720>Last 30 days</option>
1112
- </select>
1113
- <img src=images/link4.png height=10 width=10 title="Download data points (.csv)" style=cursor:pointer onclick=p40downloadEvents()>
1114
- </div>
1115
- <div>
1116
- <input value="Refresh" type="button" onclick="refreshServerTimelineStats()" />
1117
- <label><input id=p40log type="checkbox" onclick="updateServerTimelineHours()" />Log-X</label>
1118
- </div>
1119
- </div>
1120
- <canvas id=serverMainStats style=""></canvas>
1121
- </div>
1122
- <div id=p41 style="display:none">
1123
- <div id="p41title"><h1>My Server Tracing</h1></div>
1124
- <div class="areaHead">
1125
- <div class="toright2">
1126
- Show
1127
- <select id=p41limitdropdown onchange=displayServerTrace()>
1128
- <option value=100>Last 100</option>
1129
- <option value=250>Last 250</option>
1130
- <option value=500>Last 500</option>
1131
- <option value=1000>Last 1000</option>
1132
- </select>
1133
- <input value="Clear" type="button" onclick="clearServerTracing()" />
1134
- <img src=images/link4.png height=10 width=10 title="Download trace (.csv)" style=cursor:pointer onclick=p41downloadServerTrace()>
1135
- </div>
1136
- <div>
1137
- <input value="Tracing" type="button" onclick="setServerTracing()" />
1138
- <span id="p41traceStatus">None</span>
1139
- </div>
1140
- </div>
1141
- <div id=p41events style=""></div>
1142
- </div>
1143
- <div id=p42 style="display:none">
1144
- <h1>My Server Plugins</h1>
1145
- <div class="areaHead">
1146
- <div class="toright2">
1147
- </div>
1148
- <div>
1149
- <input value="Download Plugin" type="button" onclick="return pluginHandler.addPluginDlg();" />
1150
- </div>
1151
- </div>
1152
- <div id="pluginRestartNotice" class="areaHead" style="background-color:gold;display:none">
1153
- <div class="toright2">
1154
- <input value="Refresh Agent Cores" type="button" onclick="distributeCore();return false" />
1155
- </div>
1156
- <div style="padding:2px">
1157
- <div style="padding:2px"><b>Notice:</b> Plugins have been altered, this may require agent core update.</div>
1158
- </div>
1159
- </div>
1160
- <table id="p42tbl">
1161
- <tr class="DevSt"><th style="width:26px"></th><th style="width:10px"></th><th class="chName">Name</th><th class="chDescription">Description</th><th class="chSite" style="text-align:center">Link</th><th class="chVersion" style="text-align:center">Version</th><th class="chUpgradeAvail" style="text-align:center">Latest</th><th class="chStatus" style="text-align:center">Status</th><th class="chAction" style="text-align:center">Action</th><th style="width:10px"></th></tr>
1162
- </table>
1163
- <div id="pluginNoneNotice" style="width:100%;text-align:center;padding-top:10px;display:none"><i>No plugins on server.</i></div>
1164
- </div>
1165
- <div id=p43 style="display:none">
1166
- <div id="p43BackButton"><div class="backButton" tabindex=0 onclick=go(42) title="Back" onkeypress="if (event.key == 'Enter') go(42)"><div class="backButtonEx"></div></div></div>
1167
- <h1>My Server Plugins - <span id="p43title"></span></h1>
1168
- <iframe id="p43iframe" frameBorder=0 style="width:100%;height:calc(100vh - 245px);max-height:calc(100vh - 245px)"></iframe>
1169
- </div>
1170
- <div id=p50 style="display:none">
1171
- <div id="p50title"><h1>My User Groups</h1></div>
1172
- <table class="pTable">
1173
- <tr>
1174
- <td class="h1"></td>
1175
- <td class="style14">
1176
- <div style="float:right">
1177
- </div>
1178
- <div id="p50userGroupOps">
1179
- <input type=button id=UsersGroupsSelectAllButton onclick="p50usersSelectallButtonFunction()" value="Select All" />
1180
- <input type=button id=UsersGroupsGroupActionButton disabled="disabled" value="Group Action" onclick=p50usersGroupActionFunction() />
1181
- <input id=NewUserGroupButton type=button onclick=showCreateUserGroupDialog(1) value="New Group..." />
1182
- <input id=DuplicateUserGroupButton type=button style=display:none onclick=showCreateUserGroupDialog(2) value="Duplicate Group..." />
1183
- </div>
1184
- </td>
1185
- <td class="h2"></td>
1186
- </tr>
1187
- </table>
1188
- <div id="p50groups"></div>
1189
- </div>
1190
- <div id=p51 style="display:none">
1191
- <div id="p51title">
1192
- <div style="float:left"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
1193
- <h1>User Group - <span id=p51groupName></span></h1>
1194
- </div>
1195
- <div id="p51info" style="overflow-y:auto">
1196
- <table style="width:100%" cellpadding="0" cellspacing="0">
1197
- <tr>
1198
- <td style=width:auto valign=top>
1199
- <div id=p51group></div>
1200
- </td>
1201
- <td style=width:20px></td>
1202
- <td style=width:200px valign=top>
1203
- <picture id=MainUserImage style=border-width:0px;height:200px;width:200px;float:right>
1204
- <source type="image/webp" width=200 height=200 srcset="images/webp/group-256.webp" />
1205
- <img alt="" width=200 height=200 src=images/group-256.png />
1206
- </picture>
1207
- <div style="width:100%;text-align:center"><strong><span id=MainUserState></span></strong></div>
1208
- </td>
1209
- </tr>
1210
- </table>
1211
- <div id=p51group2></div>
1212
- <br />
1213
- </div>
1214
- </div>
1215
- <div id=p52 style="display:none">
1216
- <div id="p52title">
1217
- <h1>My User Recordings</h1>
1218
- </div>
1219
- <table class="pTable">
1220
- <tr>
1221
- <td class="h1"></td>
1222
- <td class="style14">
1223
- <div style="float:right">
1224
- <input type=button onclick=openRecodringPlayer() value="Open Player..." />
1225
- </div>
1226
- <div>
1227
- <input type=button onclick=refreshRecodings() value="Refresh" />
1228
- </div>
1229
- </td>
1230
- <td class="h2"></td>
1231
- </tr>
1232
- </table>
1233
- <div id=p52recordings style="overflow-y:auto"></div>
1234
- </div>
1235
- <div id=p60 style="display:none">
1236
- <div id="p60title">
1237
- <h1>My Reports</h1>
1238
- </div>
1239
- <table class="pTable">
1240
- <tr>
1241
- <td class="h1"></td>
1242
- <td class="style14">
1243
- <div style="float:right;line-height:22px">
1244
- <a id="p60downloadReportDiv" style="display:none" href=# onclick=p60downloadReport()><img src=images/link4.png height=10 width=10 title="Download Report" style=cursor:pointer></a>
1245
- </div>
1246
- <div>
1247
- <input type=button onclick=generateReportDialog() value="Generate Report..." />
1248
- </div>
1249
- </td>
1250
- <td class="h2"></td>
1251
- </tr>
1252
- </table>
1253
- <div id=p60report style="overflow-y:auto"></div>
1254
- </div>
1255
- <br id="column_l_bottomgap" />
1256
- </div>
1257
- <div id="footer">
1258
- <div class="footer1">{{{footer}}}</div>
1259
- <div class="footer2">
1260
- <a id="verifyEmailId2" style="display:none" href=# onclick="account_showVerifyEmail()">Verify Email</a>
1261
- <a id="termsLinkFooter" href=terms>Terms & Privacy</a>
1262
- </div>
1263
- </div>
1264
- <div id=dialog class="noselect" style="display:none">
1265
- <div id=dialogHeader>
1266
- <div tabindex=0 id=id_dialogclose onclick=setDialogMode() onkeypress="if (event.key == 'Enter') setDialogMode()">✖</div>
1267
- <div id=id_dialogtitle></div>
1268
- </div>
1269
- <div id=dialogBody>
1270
- <div id=dialog1>
1271
- <div id=id_dialogMessage style=""></div>
1272
- </div>
1273
- <div id=dialog2 style="">
1274
- <div id=id_dialogOptions></div>
1275
- </div>
1276
- <div id=dialog3 style="">
1277
- <div id=d3upload>
1278
- <div>File Selection</div>
1279
- <select id=d3uploadMode onchange=d3modechange()>
1280
- <option value=1>Local file upload</option>
1281
- <option value=2>Server file selection</option>
1282
- </select>
1283
- </div>
1284
- <div id=d3localmode style="display:none">
1285
- <div>Upload File</div>
1286
- <form id=d3localmodeform method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame>
1287
- <input type=text id=d3auth name=auth style="display:none" />
1288
- <input type=text id=d3filter name=filter style="display:none" />
1289
- <input type=text id=d3attrib name=attrib style="display:none" />
1290
- <input type=file id=d3localFile name=files onchange=d3setActions() />
1291
- <input type=submit id=d3submit style="display:none" />
1292
- </form>
1293
- </div>
1294
- <div id=d3servermode>
1295
- <div id=d3serveraction valign=bottom>
1296
- <input type=button id=p3FolderUp disabled="disabled" onclick=d3folderup() value="Up" /> <span id=p3CurrentFolder></span>
1297
- </div>
1298
- <div id=d3serverfiles></div>
1299
- </div>
1300
- </div>
1301
- <div id=dialog4 style="">
1302
- <input id="d4WrapButton" type="button" value="Wrap On" onclick="d4ToggleWrap()" />
1303
- <input id="d4SizeButton" type="button" value="Small" onclick="d4ToggleSize()" />
1304
- <input id="d4EncodingButton" type="button" value="Raw" onclick="d4ToggleEncoding()" />
1305
- <textarea id=d4editorarea autocomplete="off" style="height:calc(100vh - 286px);width:100%;overflow:scroll;resize:none;white-space:pre"></textarea>
1306
- </div>
1307
- <div id=dialog7 style="">
1308
- <div class="dtab">
1309
- <button id="td7meshkvm" class="tablinks" onclick="changeDesktopSettingsTab(event, 'd7meshkvm')">Agent</button>
1310
- <button id="td7rdpkvm" class="tablinks" onclick="changeDesktopSettingsTab(event, 'd7rdpkvm')">RDP</button>
1311
- <button id="td7amtkvm" class="tablinks" onclick="changeDesktopSettingsTab(event, 'd7amtkvm')">Intel® AMT</button>
1312
- </div>
1313
- <div id="d7meshkvm" class="tabcontent">
1314
- <!--<h4>Agent Remote Desktop</h4>-->
1315
- <div style="margin-top:8px">
1316
- <div>Quality</div>
1317
- <select id="d7bitmapquality" dir="rtl"></select>
1318
- </div>
1319
- <div>
1320
- <div>Scaling</div>
1321
- <select id="d7bitmapscaling" style="" dir="rtl">
1322
- <option selected=selected value=1024>100%</option>
1323
- <option value=896>87.5%</option>
1324
- <option value=768>75%</option>
1325
- <option value=640>62.5%</option>
1326
- <option value=512>50%</option>
1327
- <option value=384>37.5%</option>
1328
- <option value=256>25%</option>
1329
- <option value=128>12.5%</option>
1330
- </select>
1331
- </div>
1332
- <div>
1333
- <div>Frame rate</div>
1334
- <select id="d7framelimiter" dir="rtl">
1335
- <option selected=selected value=50>Fast</option>
1336
- <option value=100>Medium</option>
1337
- <option value=400>Slow</option>
1338
- <option value=1000>Very slow</option>
1339
- </select>
1340
- </div>
1341
- <div id="d7desktopOtherSettings">
1342
- <div>Other Settings</div>
1343
- <div id="d7otherset2" style="display:block">
1344
- <label style="display:block"><input type="checkbox" id="d7deskSwapMouse" />Swap Mouse Buttons</label>
1345
- <label style="display:block"><input type="checkbox" id="d7deskrmw" />Reverse Mouse Wheel</label>
1346
- <label style="display:block"><input type="checkbox" id="d7deskRemoteKeyMap" />Use Remote Keyboard Map</label>
1347
- <label style="display:block" id="d7deskAutoClipboardLabel"><input type="checkbox" id="d7deskAutoClipboard" />Automatic Clipboard</label>
1348
- <label style="display:block" id="d7deskAutoLockLabel"><input type="checkbox" id="d7deskAutoLock" />Lock on Disconnect</label>
1349
- </div>
1350
- </div>
1351
- </div>
1352
- <div id="d7amtkvm" class="tabcontent">
1353
- <!--<h4>Intel® AMT Hardware KVM</h4>-->
1354
- <div style="margin-top:8px">
1355
- <div>Image Encoding</div>
1356
- <select id="d7desktopmode">
1357
- <option value="1">RLE8, Fastest</option>
1358
- <option value="2">RLE16, Recommended</option>
1359
- <option value="3">RAW8, Slow</option>
1360
- <option value="4">RAW16, Very Slow</option>
1361
- </select>
1362
- </div>
1363
- <div>
1364
- <div>Other Settings</div>
1365
- <div id="d7otherset" style="display:block">
1366
- <label style="display:block"><input type="checkbox" id="d7showfocus" />Show Focus Tool</label>
1367
- <label style="display:block"><input type="checkbox" id="d7showcursor" />Show Local Mouse Cursor</label>
1368
- <label style="display:block"><input type="checkbox" id="d7localKeyMap" />Local Keyboard Map</label>
1369
- <label style="display:block"><input type="checkbox" id="d7kvmrmw" />Reverse Mouse Wheel</label>
1370
- </div>
1371
- </div>
1372
- </div>
1373
- <div id="d7rdpkvm" class="tabcontent">
1374
- <!--<h4>Remote Desktop Protocol</h4>-->
1375
- <div style="margin-top:8px">
1376
- <div>Display Size</div>
1377
- <select id="d7rdpsize">
1378
- <option value="canvas">Canvas Size</option>
1379
- <option value="browser">Browser Size</option>
1380
- <option value="screen">Screen Size</option>
1381
- <option value="640x480">640×480</option>
1382
- <option value="1024x768">1024×768</option>
1383
- <option value="1280x800">1280×800</option>
1384
- <option value="1440x900">1440×900</option>
1385
- <option value="1600x900">1600×900</option>
1386
- <option value="1680x1050">1680×1050</option>
1387
- <option value="1920x1080">1920×1080</option>
1388
- </select>
1389
- </div>
1390
- <div>
1391
- <div>Options</div>
1392
- <div id="d7rdpflags" style="display:block">
1393
- <label style="display:block"><input type="checkbox" id="d7rdp1" />Disable Wallpaper</label>
1394
- <label style="display:block"><input type="checkbox" id="d7rdp2" />Disable Full Window Drag</label>
1395
- <label style="display:block"><input type="checkbox" id="d7rdp3" />Disable Menu Animations</label>
1396
- <label style="display:block"><input type="checkbox" id="d7rdp4" />Disable Theming</label>
1397
- <label style="display:block"><input type="checkbox" id="d7rdp6" />Disable Cursor Shadow</label>
1398
- <label style="display:block"><input type="checkbox" id="d7rdp7" />Disable Cursor Settings</label>
1399
- <label style="display:block"><input type="checkbox" id="d7rdp8" />Enable Font Smooting</label>
1400
- <label style="display:block"><input type="checkbox" id="d7rdp9" />Enable Desktop Composision</label>
1401
- <label style="display:block"><input type="checkbox" id="d7rdpclip" />Automatic Clipboard</label>
1402
- <label style="display:block"><input type="checkbox" id="d7rdpsmb" />Swap Mouse Buttons</label>
1403
- <label style="display:block"><input type="checkbox" id="d7rdprmw" />Reverse Mouse Wheel</label>
1404
- </div>
1405
- </div>
1406
- </div>
1407
- </div>
1408
- </div>
1409
- <div id="idx_dlgButtonBar">
1410
- <input id="idx_dlgCancelButton" type="button" value="Cancel" style="" onclick="dialogclose(0)" />
1411
- <input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)" />
1412
- <div><input id="idx_dlgDeleteButton" type="button" value="Delete" style="display:none" onclick="dialogclose(2)" /></div>
1413
- <div id="idx_dlgMoreButtons">
1414
- <a href=# id=idx_dlgMoreButtons1 style=cursor:pointer;color:gray;text-decoration:none title="Toggle advanced options" onclick=MoreToggle(true)>▼</a>
1415
- <a href=# id=idx_dlgMoreButtons2 style=cursor:pointer;color:gray;text-decoration:none title="Toggle advanced options" onclick=MoreToggle(false)>▲</a>
1416
- </div>
1417
- </div>
1418
- </div>
1419
- <iframe name="fileUploadFrame" style="display:none"></iframe>
1420
- <form style="display:none" method=post action=uploadfile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p5fileDragName name="name" /><input id=p5fileDragAuthCookie name="auth" /><input id=p5fileDragSize name="size" /><input id=p5fileDragType name="type" /><input id=p5fileDragData name="data" /><input id=p5fileDragLink name="link" /><input type=submit id=p5loginSubmit2 style="display:none" /></form>
1421
- <form style="display:none" method=post action=uploadnodefile.ashx enctype=multipart/form-data target=fileUploadFrame><input id=p13fileDragName name="name" /><input id=p13fileDragSize name="size" /><input id=p13fileDragType name="type" /><input id=p13fileDragData name="data" /><input id=p13fileDragLink name="link" /><input type=submit id=p13loginSubmit2 style="display:none" /></form>
1422
- <audio id="chimes"><source src="sounds/chimes.mp3" type="audio/mp3" /></audio>
1423
- <iframe style=display:none name="fileDownloadFrame"></iframe>
1424
- </div>
1425
- <script type="text/javascript">
1426
- 'use strict';
1427
- var random = '{{{randomlength}}}' // Random length string for BREACH mitigation
1428
-
1429
- // Process server-side web state
1430
- var webState = '{{{webstate}}}';
1431
- if (webState != '') { webState = JSON.parse(decodeURIComponent(webState)); }
1432
- if ((webState == null) || (typeof webState != 'object')) { webState = {}; }
1433
- for (var i in webState) { if (i != 'desktopsettings') { try { localStorage.setItem(i, webState[i]); } catch (ex) {} } }
1434
- if (!webState.loctag) { try { delete localStorage.removeItem('loctag'); } catch (ex) { } }
1435
-
1436
- var args, urlargs;
1437
- var autoReconnect = true;
1438
- var powerStatetable = ['', "Powered", "Sleep", "Sleep", "Sleep", "Hibernating", "Power off", "Present"];
1439
- var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected", "Intel® AMT Connected"];
1440
- var agentsStr = ["Unknown", "Windows 32bit console", "Windows 64bit console", "Windows 32bit service", "Windows 64bit service", "Linux 32bit", "Linux 64bit", "MIPS", "XENx86", "Android", "Linux ARM", "macOS x86-32bit", "Android x86", "PogoPlug ARM", "Android", "Linux Poky x86-32bit", "macOS x86-64bit", "ChromeOS", "Linux Poky x86-64bit", "Linux NoKVM x86-32bit", "Linux NoKVM x86-64bit", "Windows MinCore console", "Windows MinCore service", "NodeJS", "ARM-Linaro", "ARMv6l / ARMv7l", "ARMv8 64bit", "ARMv6l / ARMv7l / NoKVM", "MIPS24KC (OpenWRT)", "Apple Silicon", "FreeBSD x86-64", "Unknown", "Linux ARM 64 bit (glibc/2.24 NOKVM)", "Alpine Linux x86 64 Bit (MUSL)", "Assistant (Windows)", "Armada370 - ARM32/HF (libc/2.26)", "OpenWRT x86-64", "OpenBSD x86-64", "Unknown", "Unknown", "MIPSEL24KC (OpenWRT)", "ARMADA/CORTEX-A53/MUSL (OpenWRT)", "Windows ARM 64bit console", "Windows ARM 64bit service"];
1441
- var agentsStrNoAgent = ['', '', '', '', "Windows", '', "Linux", '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', "Apple"];
1442
- var sort = 0;
1443
- var searchFocus = 0;
1444
- var mapSearchFocus = 0;
1445
- var userSearchFocus = 0;
1446
- var consoleFocus = 0;
1447
- var showRealNames = false;
1448
- var meshserver = null;
1449
- var meshes = {};
1450
- var loginTokens = {};
1451
- var meshcount = 0;
1452
- var nodes = null;
1453
- var usergroups = null;
1454
- var filetree = {};
1455
- var userinfo = null;
1456
- var serverinfo = null;
1457
- var events = [];
1458
- var users = null;
1459
- var wssessions = null;
1460
- var stars = {}; // Devices that have been "stared" by the user.
1461
- var nodeShortIdent = 0;
1462
- var desktop;
1463
- var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50, localkeymap: false, swapmouse: false, remotekeymap: false, autoclipboard: false, autolock: false };
1464
- var multidesktopsettings = { quality: 20, scaling: 128, framerate: 1000 };
1465
- var terminal;
1466
- var files;
1467
- var debugLevel = parseInt('{{{debuglevel}}}');
1468
- var features = parseInt('{{{features}}}');
1469
- var features2 = parseInt('{{{features2}}}');
1470
- var sessionTime = parseInt('{{{sessiontime}}}');
1471
- var webRelayPort = parseInt('{{{webRelayPort}}}');
1472
- var webRelayDns = '{{{webRelayDns}}}';
1473
- var sessionRefreshTimer = null;
1474
- var domain = '{{{domain}}}';
1475
- var domainUrl = '{{{domainurl}}}';
1476
- var authCookie = '{{{authCookie}}}';
1477
- var authRelayCookie = '{{{authRelayCookie}}}';
1478
- var logoutControls = JSON.parse(decodeURIComponent('{{{logoutControls}}}'));
1479
- var authCookieRenewTimer = null;
1480
- var multiDesktop = {};
1481
- var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
1482
- var amtScanResults = null;
1483
- var debugmode = 0;
1484
- var windowsBrowser = detectWindowsBrowser();
1485
- var attemptWebRTC = ((features & 128) != 0);
1486
- var passRequirements = '{{{passRequirements}}}';
1487
- if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); }
1488
- var customui = '{{{customui}}}';
1489
- if (customui != '') { customui = JSON.parse(decodeURIComponent(customui)); } else { customui = null; }
1490
- var deskAspectRatio = 0;
1491
- try { deskAspectRatio = parseInt(getstore('deskAspectRatio', '0')); } catch (ex) { }
1492
- var uiMode = parseInt(getstore('uiMode', 1));
1493
- var webPageStackMenu = false;
1494
- var webPageFullScreen = true;
1495
- var nightMode = setNightMode();
1496
- var footerBar = (getstore('footerBar', '1') == '1');
1497
- var sessionActivity = Date.now();
1498
- var updateSessionTimer = null;
1499
- var pluginHandlerBuilder = {{{pluginHandler}}};
1500
- var pluginHandler = null;
1501
- if (pluginHandlerBuilder != null) { pluginHandler = new pluginHandlerBuilder(); }
1502
- var installedPluginList = null;
1503
- var goBackStack = [];
1504
- var CollapsedGroups = {};
1505
- try { CollapsedGroups = JSON.parse(getstore('_collapse', '{}')); } catch(ex) {}
1506
- var deviceViewSettings = {};
1507
- try { deviceViewSettings = JSON.parse(getstore('_deviceViewSettings', '{}')); } catch(ex) {}
1508
- var userViewSettings = {};
1509
- try { userViewSettings = JSON.parse(getstore('_usersViewSettings', '{}')); } catch(ex) {}
1510
- var xterm = null;
1511
- var xtermfit = null;
1512
- var xtermResizeTimer = null;
1513
- var miscState = {};
1514
- var checkedNodeids = {};
1515
- var deskKeyboardShortcuts = [];
1516
- var deskKeyboardStrings = [];
1517
- var deskLastClipboardSent = null;
1518
- var requestedLastConnects = false;
1519
- var devicePagingState = null;
1520
-
1521
- // Console Message Display Timers
1522
- var p11DeskConsoleMsgTimer = null;
1523
- var p12TermConsoleMsgTimer = null;
1524
- var p13FilesConsoleMsgTimer = null;
1525
-
1526
- /*
1527
- // Check browser dark mode preference
1528
- var prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)').matches;
1529
- var prefersLightScheme = window.matchMedia('(prefers-color-scheme: light)').matches;
1530
- console.log(prefersDarkScheme, prefersLightScheme);
1531
- var mql = window.matchMedia('(prefers-color-scheme: dark)');
1532
- mql.addEventListener('change', function() { console.log('Dark Change'); });
1533
- */
1534
-
1535
- // Check if WebP is supported
1536
- var webpSupport = false;
1537
- check_webp_feature('lossy', function (f, x) { webpSupport = x; });
1538
-
1539
- function startup() {
1540
- if ((features & 32) == 0) {
1541
- // Guard against other site's top frames (web bugs).
1542
- var loc = null;
1543
- try { loc = top.location.toString().toLowerCase(); } catch (e) { }
1544
- if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
1545
- }
1546
-
1547
- // Fetch URL arguments & do sanitation
1548
- urlargs = parseUriArgs();
1549
- if (urlargs.key != null) { urlargs.key = "" + urlargs.key; }
1550
- if (urlargs.key && (isAlphaNumeric(urlargs.key) == false)) { delete urlargs.key; }
1551
- if (urlargs.locale && (isAlphaNumeric(urlargs.locale) == false)) { delete urlargs.locale; }
1552
- delete urlargs.user;
1553
- delete urlargs.pass;
1554
- delete urlargs.viewmode;
1555
- delete urlargs.gotonode;
1556
- delete urlargs.gotodevicename;
1557
- delete urlargs.gotomesh;
1558
- delete urlargs.gotouser;
1559
- delete urlargs.gotougrp;
1560
-
1561
- // Fix links if a loginKey is used
1562
- if (urlargs.key) { Q('termsLinkFooter').href += '?key=' + urlargs.key; }
1563
-
1564
- // Check if we are in debug mode
1565
- args = parseUriArgs();
1566
- if (args.key && (isAlphaNumeric(args.key) == false)) { delete args.key; }
1567
- if (args.locale && (isAlphaNumeric(args.locale) == false)) { delete args.locale; }
1568
-
1569
- if (!args.locale) { var x = getstore('loctag', 0); if ((x != null) && (x != '*')) { args.locale = x; } }
1570
- debugmode = args.debug;
1571
-
1572
- //attemptWebRTC = false; // For now, default WebRTC off unless we set it in the URL.
1573
- if (args.webrtc != null) { attemptWebRTC = (args.webrtc == 1); }
1574
-
1575
- QV('p13AutoConnect', debugmode); // Files
1576
- QV('autoconnectbutton2', debugmode); // Terminal
1577
- QV('autoconnectbutton1', debugmode); // Desktop
1578
- //QV('DeskClip', debugmode); // Clipboard feature, not completed so show in in debug mode only.
1579
-
1580
- if (nightMode) { QC('body').add('night'); QS('body')['background-color'] = '#000'; }
1581
- toggleFullScreen();
1582
-
1583
- // Setup stared devices
1584
- try { stars = JSON.parse(getstore('stars', '{}')); } catch (ex) {}
1585
-
1586
- // Setup page visuals
1587
- var hide = 0;
1588
- var globalHide = parseInt('{{{hide}}}');
1589
- if (globalHide || args.hide) {
1590
- if (args.hide) { hide = parseInt(args.hide); }
1591
- if (globalHide) { hide = (hide | globalHide); }
1592
- }
1593
- args.hide = hide;
1594
- QV('uiViewButton5', !(args.hide & 4)); // Hide the footer toggle button if footer is hidden anyway.
1595
- adjustPanels();
1596
-
1597
- // Setup logout control
1598
- var logoutControl = '';
1599
- if (logoutControls) {
1600
- if (logoutControls.name != null) { logoutControl = ('<span onclick=go(2) CLASS="LogoffLinkColor" style="cursor:pointer">' + format("Welcome {0}.", logoutControls.name) + '</span>'); }
1601
- if (logoutControls.logoutUrl != null) { logoutControl += format(' <a href="' + logoutControls.logoutUrl + '" CLASS="LogoffLinkColor">' + "Logout" + '</a>'); }
1602
- }
1603
- if (args.hide & 1) { QH('logoutControlSpan2', logoutControl); } else { QH('logoutControlSpan', logoutControl); }
1604
-
1605
- // Setup the context menu
1606
- document.onclick = function (e) { hideContextMenu(); }
1607
- document.onkeypress = ondockeypress;
1608
- document.onkeydown = ondockeydown;
1609
- document.onkeyup = ondockeyup;
1610
- //window.addEventListener('focus', ondocfocus, false);
1611
- window.addEventListener('blur', ondocblur, false);
1612
- window.onresize = function () {
1613
- hideContextMenu();
1614
- mainUpdate(512);
1615
- browserfullscreen = isBrowserFullscreen();
1616
- QV('DeskESC', browserfullscreen);
1617
- if ((xtermfit != null) && (xxcurrentView == 12)) { xtermfit.fit(); }
1618
- }
1619
- setTimeout(function() { mainUpdate(512); }, 200);
1620
-
1621
- // Connect to the mesh server
1622
- meshserver = MeshServerCreateControl(domainUrl);
1623
- meshserver.onStateChanged = onStateChanged;
1624
- meshserver.onMessage = onMessage;
1625
- meshserver.trace = args.trace;
1626
- meshserver.Start();
1627
-
1628
- // Setup page controls
1629
- Q('sortselect').selectedIndex = sort = getstore('sort', 0);
1630
- Q('sizeselect').selectedIndex = getstore('viewsize', 1);
1631
- Q('KvmSearchInput').value = Q('SearchInput').value = getstore('_search', '');
1632
- showRealNames = (getstore('showRealNames', 0) == 1);
1633
- Q('RealNameCheckBox').checked = showRealNames;
1634
- Q('DevFilterSelect').value = getstore('devFilterSelect', 0);
1635
- Q('viewselect').value = getstore('deviceView', 1);
1636
- Q('DeskControl').checked = (getstore('DeskControl', 1) == 1);
1637
- QV('accountChangeEmailAddressSpan', (features & 0x200000) == 0);
1638
-
1639
- // Display the page devices
1640
- mainUpdate(3)
1641
- for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
1642
- Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
1643
-
1644
- // Setup upload drag & drop for server files
1645
- Q('p5filetable').addEventListener('drop', p5fileDragDrop, false);
1646
- Q('p5filetable').addEventListener('dragover', p5fileDragOver, false);
1647
- Q('p5filetable').addEventListener('dragleave', p5fileDragLeave, false);
1648
- //Q('p5fileCatchAllInput').addEventListener('drop', p5fileDragDrop, false);
1649
- //Q('p5fileCatchAllInput').addEventListener('dragover', p5fileDragOver, false);
1650
- //Q('p5fileCatchAllInput').addEventListener('dragleave', p5fileDragLeave, false);
1651
-
1652
- // Setup drag & drop for device desktop
1653
- Q('deskarea0').addEventListener('drop', p11fileDragDrop, false);
1654
- Q('deskarea0').addEventListener('dragover', p11fileDragOver, false);
1655
- Q('deskarea0').addEventListener('dragleave', p11fileDragLeave, false);
1656
-
1657
- // Setup upload drag & drop for device files
1658
- Q('p13filetable').addEventListener('drop', p13fileDragDrop, false);
1659
- Q('p13filetable').addEventListener('dragover', p13fileDragOver, false);
1660
- Q('p13filetable').addEventListener('dragleave', p13fileDragLeave, false);
1661
-
1662
- // Timeline update interval
1663
- setInterval(updateDeviceTimeline, 120000); // Check every 2 minutes
1664
-
1665
- // Load desktop settings
1666
- var t = null;
1667
- try { t = localStorage.getItem('desktopsettings'); } catch (ex) {}
1668
- if (t != null) { desktopsettings = JSON.parse(t); }
1669
- t = null;
1670
- try { t = localStorage.getItem('multidesktopsettings'); } catch (ex) {}
1671
- if (t != null) { multidesktopsettings = JSON.parse(t); }
1672
- applyDesktopSettings();
1673
-
1674
- // Terminal special keys
1675
- var x = '';
1676
- for (var c = 1; c < 27; c++) x += '<option value=\'' + c + '\'>' + "Ctrl" + '-' + String.fromCharCode(64 + c) + ' (' + c + ')</option>';
1677
- QH('specialkeylist', x);
1678
-
1679
- // Setup server stats panels
1680
- setupGeneralServerStats();
1681
- setupServerTimelineStats();
1682
-
1683
- // Setup the user interface in the right mode
1684
- userInterfaceSelectMenu();
1685
-
1686
- // Setup Mesh summary panel
1687
- setupMeshSummaryStats();
1688
-
1689
- // If SSPI or LDAP authentication not used, allow batch account creation.
1690
- QV('p4UserBatchCreate', (features & 0x00080000) == 0);
1691
-
1692
- // Set the file editor
1693
- d4EditWrapVal = getstore('editorWrap', 0);
1694
- d4EditSizeVal = getstore('editorSize', 0);
1695
- d4EditEncodingVal = getstore('editorEncoding', 0);
1696
- d4ToggleWrap(true);
1697
- d4ToggleSize(true);
1698
- d4ToggleEncoding(true);
1699
- if (pluginHandler != null) pluginHandler.callHook('onWebUIStartupEnd');
1700
-
1701
- // Deleted non-english style and fix all topbar titles
1702
- if ((['en','ko','ja','zh-chs','zh-cht'].indexOf('{{{lang}}}') == -1) && ('{{{lang}}}'.toLowerCase() != '')) { QC('body').add('nonenglish'); }
1703
- var elements = document.getElementsByClassName('topbar_td');
1704
- for (var i in elements) { if (elements[i].innerHTML) { elements[i].innerHTML = elements[i].innerHTML.split(' ').join(' '); } }
1705
-
1706
- // Custom UI
1707
- if (customui != null) {
1708
- if (customui.devicesbarbuttons) {
1709
- var x = '';
1710
- for (var i in customui.devicesbarbuttons) {
1711
- var disabled = ((customui.devicesbarbuttons[i].selection == 'one') || (customui.devicesbarbuttons[i].selection == 'many'))?'disabled':'';
1712
- x += '<input id="cui:' + i + '" type="button" value="' + customui.devicesbarbuttons[i].name + '" ' + disabled + ' onclick=customUIAction(event,"devicesbarbuttons") />';
1713
- }
1714
- QH('devsCustomUIBar', x);
1715
- }
1716
- if (customui.desktopbuttons) {
1717
- var x = '';
1718
- for (var i in customui.desktopbuttons) { x += '<input id="cui:' + i + '" type="button" value="' + customui.desktopbuttons[i].name + '" style="float:left" onclick=customUIAction(event,"desktopbuttons") />'; }
1719
- QH('desktopCustomUiButtons', x);
1720
- }
1721
- if (customui.terminalbuttons) {
1722
- var x = '';
1723
- for (var i in customui.terminalbuttons) { x += '<input id="cui:' + i + '" type="button" value="' + customui.terminalbuttons[i].name + '" style="float:left" onclick=customUIAction(event,"terminalbuttons") />'; }
1724
- QH('terminalCustomUiButtons', x);
1725
- }
1726
- if (customui.filesbuttons) {
1727
- var x = '';
1728
- for (var i in customui.filesbuttons) { x += '<input id="cui:' + i + '" type="button" value="' + customui.filesbuttons[i].name + '" style="float:left" onclick=customUIAction(event,"filesbuttons") />'; }
1729
- QH('filesCustomUiButtons', x);
1730
- }
1731
- }
1732
-
1733
- // Session Refresh Timer
1734
- if (sessionTime >= 10) { sessionRefreshTimer = setTimeout(refreshCookieSession, Math.round((sessionTime * 60000) * 0.8)); }
1735
-
1736
- // Set the user's desktop shortcut keys
1737
- deskKeyboardShortcuts = [];
1738
- var deskKeyboardShortcutsStr = getstore('deskKeyShortcuts', '0x0A002E,0x100000,0x100028,0x100026,0x10004C,0x10004D,0x11004D,0x100052,0x020073,0x080057,0x020009,0x100025,0x100027').split(',');
1739
- for (var i in deskKeyboardShortcutsStr) { deskKeyboardShortcuts.push(parseInt(deskKeyboardShortcutsStr[i])); }
1740
- updateDeskShortcutKeys();
1741
-
1742
- // Set the user's desktop strings
1743
- try { deskKeyboardStrings = JSON.parse(getstore('deskStrings', '[]')); } catch (ex) {}
1744
- updateDesktopStrings();
1745
-
1746
- // Override the collapse button text
1747
- updateCollapseAllButton();
1748
-
1749
- // Make the dialog box movable
1750
- dialogBoxDrag();
1751
-
1752
- // Fix links
1753
- if (urlargs.key) { Q('p6backuplink').href += '?key=' + urlargs.key; }
1754
-
1755
- // Hide night mode button if needed
1756
- QV('uiViewButton4', (features2 & 0x00300000) == 0);
1757
-
1758
- // Fix HTML words that in english have two or more meanings
1759
- Q('DeskType').value = multiTranslate("[KeyboardTyping]|Type");
1760
- }
1761
-
1762
- function refreshCookieSession() {
1763
- var xdr = null;
1764
- try { xdr = new XDomainRequest(); } catch (e) { }
1765
- if (!xdr) xdr = new XMLHttpRequest();
1766
- xdr.open('GET', window.location.origin + domainUrl + 'refresh.ashx');
1767
- xdr.timeout = 15000;
1768
- xdr.onload = function () { sessionRefreshTimer = setTimeout(refreshCookieSession, Math.round((sessionTime * 60000) * 0.8)); };
1769
- xdr.onerror = xdr.ontimeout = function () { sessionRefreshTimer = null; };
1770
- xdr.send();
1771
- }
1772
-
1773
- // Generic handling of custom actions
1774
- function customUIAction(e, section) {
1775
- var id = e.srcElement.id;
1776
- if (id.startsWith('cui:') == false) return;
1777
- var info = customui[section][id.substring(4)];
1778
- if (info == null) return;
1779
- if (section == 'devicesbarbuttons') {
1780
- var elements = document.getElementsByClassName('DeviceCheckbox'), selectedDevices = [];
1781
- for (var i = 0; i < elements.length; i++) { if (elements[i].checked === true) { selectedDevices.push(elements[i].defaultValue.substring(6)); } }
1782
- if (typeof info.action == 'string') {
1783
- if (info.action == 'event') { meshserver.send({ action: 'uicustomevent', section: section, element: id.substring(4), selectedDevices: selectedDevices, logmsg: info.logmsg }); }
1784
- if (info.action.startsWith('dialog:')) { showCustomUiDialog(info.action.substring(7), { section: section, element: id.substring(4), selectedDevices: selectedDevices }); }
1785
- if (info.deselectdevices) { for (var i = 0; i < elements.length; i++) { elements[i].checked = false; } checkedNodeids = {}; p1updateInfo(); }
1786
- }
1787
- }
1788
- if ((section == 'devicebuttons') || (section == 'desktopbuttons') || (section == 'terminalbuttons') || (section == 'filesbuttons')) {
1789
- var selectedDevices = [ currentNode._id ];
1790
- if (typeof info.action == 'string') {
1791
- if (info.action == 'event') { meshserver.send({ action: 'uicustomevent', section: section, element: id.substring(4), selectedDevices: selectedDevices, logmsg: info.logmsg }); }
1792
- if (info.action.startsWith('dialog:')) { showCustomUiDialog(info.action.substring(7), { section: section, element: id.substring(4), selectedDevices: selectedDevices }); }
1793
- }
1794
- }
1795
- }
1796
-
1797
- // Display a generic custom UI dialog
1798
- function showCustomUiDialog(name, tag) {
1799
- if ((customui == null) || (customui.dialogs == null) || (typeof customui.dialogs[name] != 'object')) return;
1800
- var x = '', dialog = customui.dialogs[name], buttons = 3;
1801
- if (typeof dialog.text == 'string') { x += '<div style=margin-bottom:8px>' + dialog.text + '</div>'; }
1802
- if (typeof dialog.buttons == 'number') { buttons = dialog.buttons; }
1803
- if (typeof dialog.elements == 'object') {
1804
- for (var i in dialog.elements) {
1805
- var elem = dialog.elements[i];
1806
- if (elem.type == 'text') { x += addHtmlValue(elem.name, '<input id=cui:' + i + ' style=width:230px autocomplete=off />'); }
1807
- if (elem.type == 'textarea') {
1808
- if (elem.name == null) {
1809
- x += '<textarea id=cui:' + i + ' style=width:356px;resize:none;height:100px autocomplete=off></textarea>';
1810
- } else {
1811
- x += addHtmlValue(elem.name, '<textarea id=cui:' + i + ' style=width:230px;resize:none;height:100px autocomplete=off></textarea>');
1812
- }
1813
- }
1814
- if (elem.type == 'droplist') {
1815
- var y = '';
1816
- for (var j in elem.options) { y += '<option value="' + j + '">' + EscapeHtml(elem.options[j]) + '</option>'; }
1817
- x += addHtmlValue(elem.name, '<select id="cui:' + i + '" style=width:230px autocomplete=off />' + y + '</select>');
1818
- }
1819
- }
1820
- }
1821
- setDialogMode(2, dialog.title, buttons, showCustomUiDialogEx, x, { action: 'uicustomevent', section: 'dialogs', element: name, src: tag, values: {}, logmsg: dialog.logmsg });
1822
- }
1823
-
1824
- // Handle a generic custom UI dialog event
1825
- function showCustomUiDialogEx(b, t) {
1826
- if (b != 1) return;
1827
- var dialog = customui.dialogs[t.element];
1828
- if (typeof dialog.elements == 'object') {
1829
- for (var i in dialog.elements) {
1830
- var elem = dialog.elements[i];
1831
- if ((elem.type == 'droplist') || (elem.type == 'textarea') || (elem.type == 'text')) { t.values[i] = Q('cui:' + i).value; }
1832
- }
1833
- }
1834
- meshserver.send(t);
1835
- if (dialog.deselectdevices) {
1836
- var elements = document.getElementsByClassName('DeviceCheckbox')
1837
- for (var i = 0; i < elements.length; i++) { elements[i].checked = false; } checkedNodeids = {}; p1updateInfo();
1838
- }
1839
- }
1840
-
1841
- function adjustPanels() {
1842
- var hide = args.hide;
1843
- if (footerBar == false) { hide |= 4; }
1844
- QV('masthead', !(hide & 1));
1845
- QV('topbar', !(hide & 2));
1846
- QV('footer', !(hide & 4));
1847
- QV('p1title', !(hide & 8));
1848
- QV('p2title', !(hide & 8));
1849
- QV('p3title', !(hide & 8));
1850
- QV('p4title', !(hide & 8));
1851
- QV('p5title', !(hide & 8));
1852
- QV('p6title', !(hide & 8));
1853
- QV('p10title', !(hide & 8));
1854
- QV('p11title', !(hide & 8));
1855
- QV('p12title', !(hide & 8));
1856
- QV('p13title', !(hide & 8));
1857
- QV('p14title', !(hide & 8));
1858
- QV('p15title', !(hide & 8));
1859
- QV('p16title', !(hide & 8));
1860
- QV('p17title', !(hide & 8));
1861
- QV('p20title', !(hide & 8));
1862
- QV('p21title', !(hide & 8));
1863
- QV('p30title', !(hide & 8));
1864
- QV('p31title', !(hide & 8));
1865
- QV('p40title', !(hide & 8));
1866
- QV('p41title', !(hide & 8));
1867
- QV('p50title', !(hide & 8));
1868
- QV('p51title', !(hide & 8));
1869
- //if (hide & 16) { QV('page_leftbar', false); QS('page_content').left = '0px'; }
1870
- if (!footerBar) { QC('body').add('nofooter'); } else { QC('body').remove('nofooter'); }
1871
-
1872
- if (args.hide != 0) {
1873
- // Fix the main grid to zero-height elements we want to hide.
1874
- if (uiMode == 2) {
1875
- QS('container')['grid-template-rows'] = ((hide & 1) ? '0' : '66') + 'px fit-content(48px) auto ' + ((hide & 4) ? '0' : '45') + 'px';
1876
- QS('container')['-ms-grid-rows'] = ((hide & 1) ? '0' : '66') + 'px fit-content(48px) auto ' + ((hide & 4) ? '0' : '45') + 'px';
1877
- } else {
1878
- QS('container')['grid-template-rows'] = ((hide & 1) ? '0' : '66') + 'px ' + ((hide & 2) ? '0' : '24') + 'px auto ' + ((hide & 4) ? '0' : '45') + 'px';
1879
- QS('container')['-ms-grid-rows'] = ((hide & 1) ? '0' : '66') + 'px ' + ((hide & 2) ? '0' : '24') + 'px auto ' + ((hide & 4) ? '0' : '45') + 'px';
1880
- }
1881
- }
1882
-
1883
- // Adjust height of remote desktop, files and Intel AMT
1884
- // 1 = Top bar, 2 = Tool Bar, 4 = Bottom Bar, 8 = Tab Title
1885
- var xh = (((hide & 1) ? 0 : 66) + ((hide & 2) ? 0 : 24) + ((hide & 4) ? 0 : 45) + ((hide & 8) ? 0 : 60)); // 0 to 195
1886
- var xh2 = (uiMode > 1)?24:0;
1887
- QS('p2info')['height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1888
- QS('p2info')['max-height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1889
- QS('p3users')['max-height'] = 'calc(100vh - ' + (50 + xh) + 'px)'; // 124
1890
- QS('p50groups')['max-height'] = 'calc(100vh - ' + (50 + xh) + 'px)'; // 124
1891
- QS('p3events')['height'] = 'calc(100vh - ' + (50 + xh) + 'px)'; // 124
1892
- QS('p5filetable')['height'] = 'calc(100vh - ' + (99 + xh) + 'px)'; // 160
1893
- QS('p13filetable')['height'] = 'calc(100vh - ' + (127 + xh + xh2) + 'px)'; // 124
1894
- QS('serverMainStats')['height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)'; // 110
1895
- QS('serverMainStats')['max-height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)'; // 110
1896
- QS('xdevices')['max-height'] = 'calc(100vh - ' + (46 + xh) + 'px)'; // 124
1897
- QS('xdevicesmap')['max-height'] = 'calc(100vh - ' + (46 + xh) + 'px)'; // 124
1898
- QS('p15agentConsole')['height'] = 'calc(100vh - ' + (84 + xh + xh2) + 'px)';
1899
- QS('p15agentConsole')['max-height'] = 'calc(100vh - ' + (84 + xh + xh2) + 'px)';
1900
- QS('p15agentConsoleText')['height'] = 'calc(100vh - ' + (81 + xh + xh2) + 'px)';
1901
- QS('p15agentConsoleText')['max-height'] = 'calc(100vh - ' + (81 + xh + xh2) + 'px)';
1902
- var xtermActive = !((args.xterm === 0) || ((terminal != null) && (xterm == null)));
1903
- if (fullscreen) {
1904
- QS('deskarea3x')['height'] = null;
1905
- QS('deskarea3x')['max-height'] = null;
1906
- QS('p14iframe')['height'] = null;
1907
- QS('p14iframe')['max-height'] = null;
1908
- if (xtermActive) {
1909
- QS('termarea3x')['height'] = 'calc(100vh - 55px)';
1910
- QS('termarea3xdiv')['height'] = 'calc(100vh - 55px)';
1911
- QS('termarea3x')['max-width'] = 'calc(1px)';
1912
- }
1913
- } else {
1914
- QS('deskarea3x')['height'] = 'calc(100vh - ' + (74 + xh + xh2) + 'px)';
1915
- QS('deskarea3x')['max-height'] = 'calc(100vh - ' + (74 + xh + xh2) + 'px)';
1916
- QS('p14iframe')['height'] = 'calc(100vh - ' + (23 + xh + xh2) + 'px)';
1917
- QS('p14iframe')['max-height'] = 'calc(100vh - ' + (23 + xh + xh2) + 'px)';
1918
- if (xtermActive) {
1919
- QS('termarea3x')['height'] = 'calc(100vh - ' + (74 + xh + xh2) + 'px)';
1920
- QS('termarea3xdiv')['height'] = 'calc(100vh - ' + (74 + xh + xh2) + 'px)';
1921
- QS('termarea3x')['max-width'] = 'calc(1px)';
1922
- }
1923
- }
1924
- QS('p43iframe')['height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
1925
- QS('p43iframe')['max-height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
1926
- QS('p6info')['height'] = 'calc(100vh - ' + (-50 + xh + xh2) + 'px)';
1927
- QS('p6info')['max-height'] = 'calc(100vh - ' + (-50 + xh + xh2) + 'px)';
1928
- QS('p10info')['height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1929
- QS('p10info')['max-height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1930
- QS('p17info')['height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1931
- QS('p17info')['max-height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1932
- QS('p20main')['height'] = 'calc(100vh - ' + (-50 + xh + xh2) + 'px)';
1933
- QS('p20main')['max-height'] = 'calc(100vh - ' + (-50 + xh + xh2) + 'px)';
1934
- QS('p21main')['height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1935
- QS('p21main')['max-height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1936
- QS('p30info')['height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1937
- QS('p30info')['max-height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1938
- QS('p51info')['height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1939
- QS('p51info')['max-height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
1940
- QS('p16events')['height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)';
1941
- QS('p16events')['max-height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)';
1942
- QS('p31events')['height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)';
1943
- QS('p31events')['max-height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)';
1944
- QS('p41events')['height'] = 'calc(100vh - ' + (48 + xh + xh2) + 'px)';
1945
- QS('p41events')['max-height'] = 'calc(100vh - ' + (48 + xh + xh2) + 'px)';
1946
- QS('p52recordings')['height'] = 'calc(100vh - ' + (48 + xh + xh2) + 'px)';
1947
- QS('p52recordings')['max-height'] = 'calc(100vh - ' + (48 + xh + xh2) + 'px)';
1948
- QS('p60report')['height'] = 'calc(100vh - ' + (48 + xh + xh2) + 'px)';
1949
- QS('p60report')['max-height'] = 'calc(100vh - ' + (48 + xh + xh2) + 'px)';
1950
-
1951
- // We are looking at a single device, remove all the back buttons
1952
- if ((args.hide & 32) || ('{{currentNode}}'.toLowerCase() != '')) {
1953
- QV('p10BackButton', false);
1954
- QV('p11BackButton', false);
1955
- QV('p12BackButton', false);
1956
- QV('p13BackButton', false);
1957
- QV('p14BackButton', false);
1958
- QV('p15BackButton', false);
1959
- QV('p16BackButton', false);
1960
- QV('p17BackButton', false);
1961
- }
1962
- p1updateInfo();
1963
- }
1964
-
1965
- // Toggle the web page to full screen
1966
- function toggleAspectRatio(toggle) {
1967
- if (toggle === 1) { deskAspectRatio = ((deskAspectRatio + 1) % 3); putstore('deskAspectRatio', deskAspectRatio); }
1968
- deskAdjust();
1969
- }
1970
-
1971
- // If FullScreen, toggle menu to be horizontal or vertical
1972
- function toggleStackMenu(toggle) {
1973
- if (webPageFullScreen == true) {
1974
- if (toggle === 1) {
1975
- webPageStackMenu = !webPageStackMenu;
1976
- putstore('webPageStackMenu', webPageStackMenu);
1977
- }
1978
- if (webPageStackMenu == false) {
1979
- QC('body').remove('menu_stack');
1980
- } else {
1981
- QC('body').add('menu_stack');
1982
- if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
1983
- }
1984
- deskAdjust();
1985
- }
1986
- }
1987
-
1988
- // Toggle user interface menu
1989
- function showUserInterfaceSelectMenu() {
1990
- if (xxdialogMode) return;
1991
- Q('uiViewButton1').classList.remove('uiSelectorSel');
1992
- Q('uiViewButton2').classList.remove('uiSelectorSel');
1993
- Q('uiViewButton3').classList.remove('uiSelectorSel');
1994
- Q('uiViewButton4').classList.remove('uiSelectorSel');
1995
- Q('uiViewButton5').classList.remove('uiSelectorSel');
1996
- try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
1997
- QV('uiMenu', (QS('uiMenu').display == 'none'));
1998
- //Q('uiViewButton1').focus();
1999
- if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
2000
- if (footerBar) { Q('uiViewButton5').classList.add('uiSelectorSel'); }
2001
- }
2002
-
2003
- function userInterfaceSelectMenu(s) {
2004
- if (s) { uiMode = s; putstore('uiMode', uiMode); }
2005
- webPageFullScreen = (uiMode < 3);
2006
- webPageStackMenu = (uiMode > 1);
2007
- toggleFullScreen(0);
2008
- toggleStackMenu(0);
2009
- if (webPageStackMenu && (xxcurrentView >= 10)) { QC('column_l').add('room4submenu'); } else { QC('column_l').remove('room4submenu'); }
2010
- adjustPanels();
2011
- }
2012
-
2013
- function toggleNightMode() {
2014
- if (xxdialogMode) return;
2015
- var cNightMode = getstore('nightMode', '0');
2016
- var x = '<input type=radio id=night0 name=nightmoderadio value=0 ' + ((cNightMode == 0)?'checked':'') + '><label for=night0>' + "Browser default" + '</label><br>';
2017
- x += '<input type=radio id=night2 name=nightmoderadio value=2 ' + ((cNightMode == 2)?'checked':'') + '><label for=night2>' + "Light mode" + '</label><br>';
2018
- x += '<input type=radio id=night1 name=nightmoderadio value=1 ' + ((cNightMode == 1)?'checked':'') + '><label for=night1>' + "Dark mode" + '</label><br>';
2019
- setDialogMode(2, "Night Mode", 3, toggleNightModeEx, x);
2020
- QV('uiMenu', false);
2021
- }
2022
-
2023
- function toggleNightModeEx() {
2024
- // Save new night mode
2025
- var nNightMode = '0';
2026
- if (Q('night1').checked) { nNightMode = '1'; }
2027
- if (Q('night2').checked) { nNightMode = '2'; }
2028
- putstore('nightMode', nNightMode);
2029
- setNightMode();
2030
- }
2031
-
2032
- function setNightMode() {
2033
- // Set night mode
2034
- var nNightMode = getstore('nightMode', '0')
2035
- nightMode = false;
2036
- if ((features2 & 0x00100000) != 0) { nNightMode = '1'; }
2037
- if ((features2 & 0x00200000) != 0) { nNightMode = '2'; }
2038
- if (nNightMode == '1') { nightMode = true; }
2039
- else if ((nNightMode == '0') && (window.matchMedia)) { nightMode = window.matchMedia('(prefers-color-scheme: dark)').matches }
2040
- if (nightMode) { QC('body').add('night'); QS('body')['background-color'] = '#000'; } else { QC('body').remove('night'); QS('body')['background-color'] = '#d3d9d6'; }
2041
- return nightMode;
2042
- }
2043
-
2044
- function toggleFooterBarMode() {
2045
- footerBar = !footerBar;
2046
- putstore('footerBar', footerBar?'1':'0');
2047
- QS('container')['grid-template-rows'] = null;
2048
- QS('container')['-ms-grid-rows'] = null;
2049
- adjustPanels();
2050
- }
2051
-
2052
- // Toggle the web page to full screen
2053
- function toggleFullScreen(toggle) {
2054
- if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
2055
- if (webPageFullScreen == false) {
2056
- QC('body').remove('menu_stack');
2057
- QC('body').remove('fullscreen');
2058
- QC('body').remove('arg_hide');
2059
- if (xxcurrentView >= 10) QC('column_l').add('room4submenu');
2060
- QV('UserDummyMenuSpan', false);
2061
- //QV('page_leftbar', false);
2062
- } else {
2063
- QC('body').add('fullscreen');
2064
- if (args.hide & 16) QC('body').add('arg_hide');
2065
- QV('page_leftbar', !(args.hide & 16));
2066
- QV('MainMenuSpan', !(args.hide & 16));
2067
- if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
2068
- QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
2069
- }
2070
- mainUpdate(512);
2071
- QV('body', true);
2072
- }
2073
-
2074
- function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; }
2075
- function reload() {
2076
- var x = window.location.href;
2077
- if (x.endsWith('/#')) { x = x.substring(0, x.length - 2); }
2078
- window.location.href = x;
2079
- }
2080
-
2081
- function onStateChanged(server, state, prevState, errorCode) {
2082
- if (state == 0) {
2083
- // Control web socket disconnected
2084
- setDialogMode(0); // Close any dialog boxes if present
2085
- go(0); // Go to disconnection panel
2086
-
2087
- // Clean up
2088
- powerTimeline = null;
2089
- powerTimelineReq = null;
2090
- powerTimelineNode = null;
2091
- powerTimelineUpdate = null;
2092
- deviceShares = null;
2093
- deleteAllNotifications(); // Close and clear notifications if present
2094
- hideContextMenu(); // Hide the context menu if present
2095
- QV('verifyEmailId2', false);
2096
- QV('logoutControl', false);
2097
- if (errorCode == 'noauth') { QH('p0span', "Unable to perform authentication"); return; }
2098
- if (prevState == 2) { if (autoReconnect) { setTimeout(serverPoll, 5000); } } else { QH('p0span', "Unable to connect web socket"); }
2099
- if (authCookieRenewTimer != null) { clearInterval(authCookieRenewTimer); authCookieRenewTimer = null; }
2100
- } else if (state == 2) {
2101
- // Fetch list of meshes, nodes, files
2102
- meshserver.send({ action: 'usergroups' });
2103
- meshserver.send({ action: 'meshes' });
2104
- meshserver.send({ action: 'nodes', id: '{{currentNode}}', skip: (devicePagingState == null) ? 0 : devicePagingState.skip });
2105
- meshserver.send({ action: 'loginTokens' });
2106
- if (pluginHandler != null) { meshserver.send({ action: 'plugins' }); }
2107
- if ('{{currentNode}}'.toLowerCase() == '') { meshserver.send({ action: 'files' }); }
2108
- if ('{{viewmode}}'.toLowerCase() == '') { go(1); }
2109
- authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
2110
- if (xxcurrentView == 40) { refreshServerTimelineStats(); }
2111
- }
2112
- }
2113
-
2114
- // Poll the server, if it responds, refresh the page.
2115
- function serverPoll() {
2116
- var xdr = null;
2117
- try { xdr = new XDomainRequest(); } catch (e) { }
2118
- if (!xdr) xdr = new XMLHttpRequest();
2119
- xdr.open('HEAD', window.location.href);
2120
- xdr.timeout = 15000;
2121
- // Make sure there isn't a reverse proxy in front that may just be returning 5xx codes
2122
- // Status code 4xx should still be allowed, since a page could potentially be removed, etc
2123
- xdr.onload = function () { if (xdr.status < 500) reload(); else setTimeout(serverPoll, 10000); };
2124
- xdr.onerror = xdr.ontimeout = function () { setTimeout(serverPoll, 10000); };
2125
- xdr.send();
2126
- }
2127
-
2128
- // Return true if this browser is Windows based
2129
- function detectWindowsBrowser() {
2130
- var userAgent = window.navigator.userAgent.toUpperCase();
2131
- return (userAgent.indexOf('WINDOWS') >= 0) || (userAgent.indexOf('WIN32') >= 0) || (userAgent.indexOf('WIN64') >= 0);
2132
- }
2133
-
2134
- function updateSiteAdmin() {
2135
- var serverFeatures = parseInt('{{{serverfeatures}}}');
2136
- var siteRights = userinfo.siteadmin;
2137
- var accountSettingsLocked = ((siteRights != 0xFFFFFFFF) && ((siteRights & 1024) != 0)) || ((features2 & 0x100) != 0); // Not admin and have account features locked, or using a loginToken
2138
-
2139
- // Update account actions
2140
- QV('p2AccountSecurity', ((features & 4) == 0) && (serverinfo.domainauth == false) && ((features & 4096) != 0) && (accountSettingsLocked == false)); // Hide Account Security if in single user mode or domain authentication, 2 factor auth not supported.
2141
- QV('p2AccountActions', !accountSettingsLocked)
2142
- QV('managePhoneNumber1', (features & 0x02000000) && (features & 0x04000000) && (serverinfo.lock2factor != true));
2143
- QV('managePhoneNumber2', (features & 0x02000000) && !(features & 0x04000000) && (serverinfo.lock2factor != true));
2144
- QV('manageMessaging1', (features2 & 0x02000000) && (features2 & 0x04000000) && (serverinfo.lock2factor != true));
2145
- QV('manageMessaging2', (features2 & 0x02000000) && !(features2 & 0x04000000) && (serverinfo.lock2factor != true));
2146
- QV('manageEmail2FA', (features & 0x00800000) && (serverinfo.lock2factor != true));
2147
- QV('p2AccountPassActions', ((features & 4) == 0) && (serverinfo.domainauth == false) && (userinfo != null) && (userinfo._id.split('/')[2].startsWith('~') == false)); // Hide Account Actions if in single user mode or domain authentication
2148
- //QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
2149
- QV('accountCreateLoginTokenSpan', features2 & 0x00000080);
2150
- QV('p2AccountImageFrame', !accountSettingsLocked)
2151
- QV('p2ServerActions', (siteRights & 21) && ((serverFeatures & 15) != 0));
2152
- QV('LeftMenuMyServer', (siteRights & 21) && ((serverFeatures & 64) != 0)); // 16 + 4 + 1
2153
- QV('MainMenuMyServer', siteRights & 21);
2154
- QV('p2ServerActionsBackup', (siteRights & 1) && ((serverFeatures & 1) != 0));
2155
- QV('p2ServerActionsRestore', (siteRights & 4) && ((serverFeatures & 2) != 0));
2156
- QV('p2ServerActionsVersion', (siteRights & 16) && ((serverFeatures & 4) != 0));
2157
- QV('p2ServerActionsErrors', (siteRights & 16) && ((serverFeatures & 8) != 0));
2158
- QV('MainMenuMyFiles', siteRights & 8);
2159
- QV('LeftMenuMyFiles', siteRights & 8);
2160
- if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
2161
- if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
2162
-
2163
- // Update user image
2164
- if ((userinfo.flags != null) && (userinfo.flags & 1)) {
2165
- if (userinfo.accountImageRnd == null) { userinfo.accountImageRnd = Math.floor(Math.random() * 9999999999); }
2166
- Q('p2AccountImage').src = 'userimage.ashx?rnd=' + userinfo.accountImageRnd;
2167
- } else {
2168
- Q('p2AccountImage').src = 'images/user-256.png';
2169
- }
2170
-
2171
- // Update user management state
2172
- if ((userinfo.siteadmin & 2) != 0) {
2173
- // We are user administrator
2174
- if (users == null) { meshserver.send({ action: 'users' }); }
2175
- if (wssessions == null) { meshserver.send({ action: 'wssessioncount' }); }
2176
- mainUpdate(8192 + 16384);
2177
- } else {
2178
- // We are not user administrator
2179
- users = null;
2180
- wssessions = null;
2181
- mainUpdate(16384);
2182
- if (xxcurrentView == 4 || ((xxcurrentView >= 30) && (xxcurrentView < 40))) { setDialogMode(0); go(1); currentUser = null; }
2183
- }
2184
- meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
2185
- QV('ServerConsole', (userinfo.siteadmin === 0xFFFFFFFF) && ((serverFeatures & 16) != 0));
2186
- QV('ServerTrace', (userinfo.siteadmin === 0xFFFFFFFF) && ((serverFeatures & 32) != 0));
2187
- if ((xxcurrentView == 115) && (userinfo.siteadmin != 0xFFFFFFFF)) { go(6); }
2188
- if ((xxcurrentView == 6) && ((userinfo.siteadmin & 21) == 0)) { go(1); }
2189
-
2190
- // If we are site administrator, register to get server statistics
2191
- if ((siteRights & 21) != 0) { meshserver.send({ action: 'serverstats', interval: 10000 }); }
2192
- }
2193
-
2194
- // To boost the speed of the web page when even floods occur, this method perform a delayed update on the web page.
2195
- var updateNaggleTimer = null;
2196
- var updateNaggleFlags = 0;
2197
- function mainUpdate(flags) {
2198
- updateNaggleFlags |= flags;
2199
- if (updateNaggleTimer == null) {
2200
- updateNaggleTimer = setTimeout(function () {
2201
- if (updateNaggleFlags & 512) { center(); }
2202
- if (updateNaggleFlags & 1) { onSearchInputChanged(); }
2203
- if (updateNaggleFlags & 2) { onSortSelectChange(false); }
2204
- if (updateNaggleFlags & 128) { updateMeshes(); }
2205
- if (updateNaggleFlags & 4) { updateDevices(); updateDeviceDetails(); if (xxcurrentView == 21) { p21updateMesh(); } }
2206
- if (updateNaggleFlags & 8) { drawNotifications(); }
2207
- if ((updateNaggleFlags & 16) && (features & 0x00008000)) { updateMapMarkers(); }
2208
- if (updateNaggleFlags & 32) { eventsUpdate(); }
2209
- if ((updateNaggleFlags & 64) && (features & 0x00008000)) { refreshMap(false, true); }
2210
- if (updateNaggleFlags & 256) { drawDeviceTimeline(); }
2211
- if (updateNaggleFlags & 1024) { deviceEventsUpdate(); }
2212
- if (updateNaggleFlags & 2048) { userEventsUpdate(); }
2213
- if (updateNaggleFlags & 4096) { p20updateMesh(); }
2214
- if (updateNaggleFlags & 8192) { updateUserGroups(); }
2215
- if (updateNaggleFlags & 16384) { updateUsers(); }
2216
- if (updateNaggleFlags & 32768) { updateRecordings(); }
2217
- if (updateNaggleFlags & 65536) { updateLoginTokens(); }
2218
- updateNaggleTimer = null;
2219
- updateNaggleFlags = 0;
2220
- gotoStartViewPage();
2221
- }, 150);
2222
- }
2223
- }
2224
-
2225
- // Return the number of 2nd factor for this account
2226
- function count2factoraAuths() {
2227
- if (userinfo == null) return -1;
2228
- var authFactorCount = 0;
2229
- if (userinfo.otpsecret == 1) { authFactorCount++; } // Authenticator time factor
2230
- if (userinfo.otphkeys > 0) { authFactorCount += userinfo.otphkeys; } // FIDO hardware factor
2231
- if ((features & 0x00800000) && (userinfo.otpekey == 1)) { authFactorCount++; } // EMail factor
2232
- if ((features & 0x02000000) && (features & 0x04000000) && (userinfo.phone != null)) { authFactorCount++; } // SMS factor
2233
- if ((features2 & 0x02000000) && (features2 & 0x04000000) && (userinfo.msghandle != null)) { authFactorCount++; } // Messaging factor
2234
- if ((authFactorCount > 0) && (userinfo.otpkeys > 0) && ((features2 & 0x40000) == 0)) { authFactorCount++; } // Backup keys
2235
- return authFactorCount;
2236
- }
2237
-
2238
- var backupCodesWarningDone = false;
2239
- function updateSelf() {
2240
- var authFactorCount = count2factoraAuths(); // Get the number of 2nd factors
2241
- var accountSettingsLocked = ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 1024) != 0));
2242
- QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
2243
- QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true) && (accountSettingsLocked == false));
2244
- QV('manageOtp', (serverinfo.lock2factor != true) && (authFactorCount > 0) && ((features2 & 0x40000) == 0));
2245
- QV('authPhoneNumberCheck', (userinfo.phone != null));
2246
- QV('authMessagingCheck', (userinfo.msghandle != null));
2247
- QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));
2248
- QV('authAppSetupCheck', userinfo.otpsecret == 1);
2249
- QV('manageAuthApp', (serverinfo.lock2factor != true) && ((userinfo.otpsecret == 1) || ((features2 & 0x00020000) == 0)));
2250
- QV('authKeySetupCheck', userinfo.otphkeys > 0);
2251
- QV('authPushAuthDevCheck', (userinfo.otpdev > 0) && ((features2 & 0x40) != 0));
2252
- QV('authCodesSetupCheck', userinfo.otpkeys > 0);
2253
- QV('managePushAuthDev', (serverinfo.lock2factor != true) && (features2 & 0x40) && (authFactorCount > 0));
2254
- QV('manageHardwareOtp', (serverinfo.lock2factor != true));
2255
- mainUpdate(4 + 128 + 4096);
2256
-
2257
- // Check if none or at least 2 factors are enabled.
2258
- if ((backupCodesWarningDone == false) && (authFactorCount == 1) && ((features2 & 0x80000) == 0)) {
2259
- addNotification({ text: "Please add two-factor backup codes. If the current factor is lost, there is no way to recover this account.", title: "Two factor authentication", tag: 'backupcodes' });
2260
- backupCodesWarningDone = true;
2261
- }
2262
-
2263
- // If we can't create new groups, hide all links that can do that.
2264
- var newGroupsAllowed = ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 64) == 0));
2265
- QV('p2createMeshLink1', newGroupsAllowed);
2266
- QV('p2createMeshLink2', newGroupsAllowed);
2267
- QV('getStarted1', newGroupsAllowed);
2268
- QV('getStarted2', !newGroupsAllowed);
2269
-
2270
- if (typeof userinfo.passchange == 'number') {
2271
- if (userinfo.passchange == -1) { QH('p2nextPasswordUpdateTime', " - Reset on next login."); }
2272
- else if ((passRequirements != null) && (typeof passRequirements.reset == 'number')) {
2273
- var seconds = (userinfo.passchange) + (passRequirements.reset * 86400) - Math.floor(Date.now() / 1000);
2274
- if (seconds < 0) { QH('p2nextPasswordUpdateTime', " - Reset on next login."); }
2275
- else if (seconds < 3600) { var secs = Math.floor(seconds / 60); QH('p2nextPasswordUpdateTime',format((secs == 1)?" - Reset in 1 minute.":" - Reset in {0} minutes.", secs)); }
2276
- else if (seconds < 86400) { var hours = Math.floor(seconds / 3600); QH('p2nextPasswordUpdateTime', format((hours == 1) ? " - Reset in 1 hour." : " - Reset in {0} hours.", hours)); }
2277
- else { var days = Math.floor(seconds / 86400); QH('p2nextPasswordUpdateTime', format((hours == 1) ? " - Reset in 1 day." : " - Reset in {0} days.", days)); }
2278
- }
2279
- }
2280
-
2281
- // Adjust "My Users" tabs
2282
- QV('MainMenuMyUsers', ((users != null) && ((features & 4) == 0)) || (((userinfo.siteadmin & 512) != 0) && ((features & 0x08000000) != 0)));
2283
- QV('LeftMenuMyUsers', ((users != null) && ((features & 4) == 0)) || (((userinfo.siteadmin & 512) != 0) && ((features & 0x08000000) != 0)));
2284
- QV('UsersGeneral', ((users != null) && ((features & 4) == 0)));
2285
- QV('UsersGroups', ((users != null) && ((features & 4) == 0)));
2286
- QV('UsersRecordings', ((userinfo.siteadmin & 512) != 0) && ((features & 0x08000000) != 0));
2287
- }
2288
-
2289
- function setSessionActivity() { sessionActivity = Date.now(); QH('idleTimeoutNotify', ''); }
2290
- function checkIdleSessionTimeout() {
2291
- var delta = (Date.now() - sessionActivity);
2292
- if (delta > serverinfo.timeout) { window.location.href = 'logout'; } else {
2293
- var ds = Math.round((serverinfo.timeout - delta) / 1000);
2294
- if (ds <= 60) {
2295
- QH('idleTimeoutNotify', '<br />' + format((ds == 1)?"1 second until disconnect":"{0} seconds until disconnect", ds));
2296
- } else {
2297
- ds = Math.round(ds / 60);
2298
- if (ds <= 5) { QH('idleTimeoutNotify', '<br />' + format((ds == 1)?"1 minute until disconnect":"{0} minutes until disconnect", ds)); }
2299
- }
2300
- }
2301
- }
2302
-
2303
- function onMessage(server, message) {
2304
- switch (message.action) {
2305
- case 'trace': {
2306
- serverTrace.unshift(message);
2307
- displayServerTrace();
2308
- break;
2309
- }
2310
- case 'intersession' : {
2311
- if (message.subaction == 'removeNotify') { notificationDelete(message.id); }
2312
- break;
2313
- }
2314
- case 'traceinfo': {
2315
- if (typeof message.traceSources == 'object') {
2316
- if ((message.traceSources != null) && (message.traceSources.length > 0)) {
2317
- serverTraceSources = message.traceSources;
2318
- QH('p41traceStatus', EscapeHtml(message.traceSources.join(', ')));
2319
- } else {
2320
- serverTraceSources = [];
2321
- QH('p41traceStatus', "None");
2322
- }
2323
- }
2324
- break;
2325
- }
2326
- case 'serverstats': {
2327
- updateGeneralServerStats(message);
2328
- break;
2329
- }
2330
- case 'serverwarnings': {
2331
- if ((message.warnings != null) && (message.warnings.length > 0)) {
2332
- var ServerWarnings = {
2333
- 1: "MeshCentral SSH support requires NodeJS 11 or higher.",
2334
- 2: "Missing WebDAV parameters.",
2335
- 3: "Unrecognized configuration option \"{0}\".",
2336
- 4: "WebSocket compression is disabled, this feature is broken in NodeJS v11.11 to v12.15 and v13.2",
2337
- 5: "Unable to load Intel AMT TLS root certificate for default domain.",
2338
- 6: "Unable to load Intel AMT TLS root certificate for domain {0}.",
2339
- 7: "CIRA local FQDN's ignored when server in LAN-only or WAN-only mode.",
2340
- 8: "Can't have more than 4 CIRA local FQDN's. Ignoring value.",
2341
- 9: "Agent hash checking is being skipped, this is unsafe.",
2342
- 10: "Missing Let's Encrypt email address.",
2343
- 11: "Invalid Let's Encrypt host names.",
2344
- 12: "Invalid Let's Encrypt names, can't contain a *.",
2345
- 13: "Unable to setup Let's Encrypt module.",
2346
- 14: "Invalid Let's Encrypt names, unable to resolve: {0}",
2347
- 15: "Invalid Let's Encrypt email address, unable to resolve: {0}",
2348
- 16: "Unable to load CloudFlare trusted proxy IPv6 address list.",
2349
- 17: "SendGrid server has limited use in LAN mode.",
2350
- 18: "SMTP server has limited use in LAN mode.",
2351
- 19: "SMS gateway has limited use in LAN mode.",
2352
- 20: "Invalid \"LoginCookieEncryptionKey\" in config.json.",
2353
- 21: "Backup path can't be set within meshcentral-data folder, backup settings ignored.",
2354
- 22: "Failed to sign agent {0}: {1}",
2355
- 23: "Unable to load agent icon file: {0}.",
2356
- 24: "Unable to load agent logo file: {0}.",
2357
- 25: "This NodeJS version does not support OpenID.",
2358
- 26: "This NodeJS version does not support Discord.js."
2359
- };
2360
- var x = '';
2361
- for (var i in message.warnings) {
2362
- var y = message.warnings[i];
2363
- if (typeof y == 'string') {
2364
- x += '<div style=color:red;padding-bottom:6px><b>' + "WARNING: " + y + '</b></div>';
2365
- } else {
2366
- var z = ServerWarnings[y.id];
2367
- if (z == null) { z = y.msg; } else { if (y.args != null) { z = format(z, ...y.args); } }
2368
- x += '<div style=color:red;padding-bottom:6px><b>' + "WARNING: " + z + '</b></div>';
2369
- }
2370
- }
2371
- QH('serverWarnings', x);
2372
- QV('serverWarningsDiv', true);
2373
- }
2374
- break;
2375
- }
2376
- case 'servertimelinestats': {
2377
- setServerTimelineStats(message.events);
2378
- break;
2379
- }
2380
- case 'authcookie': {
2381
- // Got an authentication cookie refresh
2382
- authCookie = message.cookie;
2383
- authRelayCookie = message.rcookie;
2384
- break;
2385
- }
2386
- case 'serverinfo': {
2387
- serverinfo = message.serverinfo;
2388
- if (serverinfo.timeout) { setInterval(checkIdleSessionTimeout, 10000); checkIdleSessionTimeout(); }
2389
- if (debugmode == 1) { console.log('Server time: ', printDateTime(new Date(serverinfo.serverTime))); }
2390
- setupServiceWorker();
2391
- if (serverinfo.certExpire != null) {
2392
- var days = Math.floor((serverinfo.certExpire - Date.now()) / 86400000);
2393
- if ((days >= 0) && (days < 20)) {
2394
- QH('serverCertWarnings', '<div style=color:red;padding-bottom:6px><b>' + "WARNING: " + format("Certificate expires in {0} day(s)", days) + '</b></div>');
2395
- QV('serverWarningsDiv', true);
2396
- addNotification({ text: format("Certificate expires in {0} day(s)", days) });
2397
- }
2398
- }
2399
- if (serverinfo.preConfiguredRemoteInput) {
2400
- // Setup the pre-configured keyboard remote input strings
2401
- var x = '';
2402
- for (var i in serverinfo.preConfiguredRemoteInput) { x += '<div class="cmtext" onclick="cmdeskpreconfigtypeaction(' + i + ',event)">' + EscapeHtml(serverinfo.preConfiguredRemoteInput[i].name) + '</div>'; }
2403
- if (x != '') { x += '<hr />'; }
2404
- QH('deskPreConfigShortcutContextMenu1', x);
2405
- }
2406
- if (serverinfo.preConfiguredScripts) {
2407
- // Setup the pre-configured scripts
2408
- var x = '', y = '';
2409
- for (var i in serverinfo.preConfiguredScripts) {
2410
- var s = serverinfo.preConfiguredScripts[i];
2411
- var z = '<div class="cmtext" onclick="cmdeskpreconfigscriptaction(' + i + ',event)">' + EscapeHtml(serverinfo.preConfiguredScripts[i].name) + '</div>';
2412
- if (s.type != 3) { x += z; }
2413
- if (s.type >= 3) { y += z; }
2414
- }
2415
- QH('deskPreConfigScriptContextMenu1', x); // Windows devices
2416
- QH('deskPreConfigScriptContextMenu2', y); // Other devices
2417
- }
2418
- break;
2419
- }
2420
- case 'userinfo': {
2421
- userinfo = message.userinfo;
2422
- updateSiteAdmin();
2423
- updateSelf();
2424
- break;
2425
- }
2426
- case 'users': {
2427
- users = {};
2428
- for (var m in message.users) { users[message.users[m]._id] = message.users[m]; }
2429
- if (currentUser != null) { currentUser = users[currentUser._id]; }
2430
- mainUpdate(16384);
2431
- updateSelf();
2432
- break;
2433
- }
2434
- case 'wssessioncount': {
2435
- wssessions = message.wssessions;
2436
- mainUpdate(16384);
2437
- break;
2438
- }
2439
- case 'meshes': {
2440
- meshes = {};
2441
- for (var m in message.meshes) { meshes[message.meshes[m]._id] = message.meshes[m]; }
2442
- if (currentMesh != null) { currentMesh = meshes[currentMesh._id]; }
2443
- mainUpdate(4 + 128);
2444
- break;
2445
- }
2446
- case 'usergroups': {
2447
- var groupCount = 0;
2448
- if (Array.isArray(message.ugroups)) {
2449
- usergroups = {};
2450
- for (var i in message.ugroups) { groupCount++; usergroups[message.ugroups[i]._id] = message.ugroups[i]; }
2451
- if (groupCount == 0) { usergroups = null; }
2452
- } else {
2453
- usergroups = message.ugroups;
2454
- for (var i in message.ugroups) { groupCount++; message.ugroups[i]._id = i; }
2455
- if (groupCount == 0) { usergroups = null; }
2456
- }
2457
- mainUpdate(8192);
2458
- break;
2459
- }
2460
- case 'files': {
2461
- filetree = setupBackPointers(message.filetree);
2462
- updateFiles();
2463
- d3updatefiles();
2464
- break;
2465
- }
2466
- case 'nodes': {
2467
- nodes = [];
2468
- for (var m in message.nodes) {
2469
- for (var n in message.nodes[m]) {
2470
- if (message.nodes[m][n]._id == null) { console.log('Invalid node (' + n + '): ' + JSON.stringify(message.nodes)); continue; }
2471
- if (message.nodes[m][n].name == null) { message.nodes[m][n].name = '???'; }
2472
- message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
2473
- if (message.nodes[m][n].rname) { message.nodes[m][n].rnamel = message.nodes[m][n].rname.toLowerCase(); } else { message.nodes[m][n].rnamel = message.nodes[m][n].namel; }
2474
- message.nodes[m][n].meshnamel = meshes[m]?meshes[m].name.toLowerCase():'*';
2475
- message.nodes[m][n].meshid = m;
2476
- message.nodes[m][n].state = (message.nodes[m][n].state)?(message.nodes[m][n].state):0;
2477
- if (!message.nodes[m][n].icon) message.nodes[m][n].icon = 1;
2478
- message.nodes[m][n].ident = ++nodeShortIdent;
2479
- nodes.push(message.nodes[m][n]);
2480
- }
2481
- }
2482
-
2483
- // Remove any stars for nodes that don't exist
2484
- for (var i in stars) { if (getNodeFromId(i) == null) { delete stars[i]; } }
2485
-
2486
- // If we are currently looking at a node this is now gone, change the view.
2487
- if ((currentNode != null) && (IsNodeViewable(currentNode) == false)) { currentNode = null; go(1); }
2488
-
2489
- // Change the reference to the current node
2490
- if (currentNode != null) { currentNode = getNodeFromId(currentNode._id); if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); } else { go(1); } }
2491
-
2492
- // Update device paging
2493
- devicePagingState = (message.totalcount == null) ? null : { total: message.totalcount, skip: message.skip, limit: message.limit };
2494
- updateDevicePageState();
2495
-
2496
- mainUpdate(1 | 2 | 4 | 64);
2497
- break;
2498
- }
2499
- case 'powertimeline': {
2500
- if (message.nodeid != powerTimelineReq) break;
2501
- powerTimelineNode = message.nodeid;
2502
- powerTimeline = message.timeline;
2503
- powerTimelineUpdate = Date.now() + 300000; // Update every 5 minutes
2504
- for (var i in powerTimeline) { if (i % 2 == 1) { powerTimeline[i] = powerTimeline[i] * 1000; } } // Decompress time
2505
- if (currentNode._id == message.nodeid) { mainUpdate(256); }
2506
- break;
2507
- }
2508
- case 'deviceShares': {
2509
- if (message.nodeid != deviceSharesReq) break;
2510
- deviceSharesNode = message.nodeid;
2511
- deviceShares = message.deviceShares;
2512
- if ((currentNode != null) && (currentNode._id == message.nodeid)) { gotoDevice(currentNode._id, xxcurrentView, true); }
2513
- break;
2514
- }
2515
- case 'deviceMeshShares': {
2516
- if (message.meshid != deviceSharesReq) break;
2517
- deviceSharesNode = message.meshid;
2518
- deviceShares = message.deviceShares;
2519
- if ((currentMesh != null) && (currentMesh._id == message.meshid)) { p20updateMesh(); }
2520
- break;
2521
- }
2522
- case 'getsysinfo': {
2523
- if (message.nodeid != powerTimelineReq) break;
2524
- if (message.noinfo === true) {
2525
- updateDeviceDetails(getNodeFromId(message.nodeid));
2526
- } else {
2527
- updateDeviceDetails(getNodeFromId(message.nodeid), message.hardware);
2528
- }
2529
- break;
2530
- }
2531
- case 'lastconnect': {
2532
- var node = getNodeFromId(message.nodeid);
2533
- if (node != null) {
2534
- node.lastconnect = message.time;
2535
- node.lastaddr = message.addr;
2536
- if ((currentNode._id == node._id) && (Q('MainComputerState').innerHTML == '') && (node.lastconnect != null)) {
2537
- QH('MainComputerState', '<span>' + "Last seen:" + '<br />' + printDateTime(new Date(node.lastconnect)) + '</span>');
2538
- }
2539
- }
2540
- break;
2541
- }
2542
- case 'lastconnects': {
2543
- var lcnodes = Object.keys(message.lastconnects);
2544
- for (var i in lcnodes) {
2545
- var lcnodeid = lcnodes[i];
2546
- var node = getNodeFromId(lcnodeid);
2547
- if (node != null) { node.lastconnect = message.lastconnects[lcnodeid] }
2548
- }
2549
- mainUpdate(4);
2550
- }
2551
- case 'msg': {
2552
- // Check if this is a message from a node
2553
- if (message.nodeid != null) {
2554
- var index = -1;
2555
- if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == message.nodeid) { index = i; break; } } }
2556
- if (index != -1) {
2557
- // Node was found, dispatch the message
2558
- if ((message.type === 'cpuinfo') && (currentNode != null) && (currentNode._id == message.nodeid)) {
2559
- var now = (Date.now() / 1000), cpu = 0, memory = 0;
2560
- if (typeof message.cpu.total == 'number') { cpu = message.cpu.total; }
2561
- if (typeof message.memory.percentConsumed == 'number') { memory = message.memory.percentConsumed; }
2562
- deviceDetailsStatsData.push([now, cpu, memory]);
2563
- deviceDetailsStatsDraw(message);
2564
- } else if (message.type === 'console') { p15consoleReceive(nodes[index], message.value, message.source); } // This is a console message.
2565
- else if (message.type === 'notify') { // This is a notification message.
2566
- var n = getstore('notifications', 0);
2567
- if (((n & 8) == 0) && (message.amtMessage != null)) { break; } // Intel AMT desktop & terminal messages should be ignored.
2568
- var n = { text: message.value, title: message.title, icon: message.icon, titleid: message.titleid, msgid: message.msgid, args: message.args };
2569
- if (message.id != null) { n.id = message.id; }
2570
- if (message.nodeid != null) { n.nodeid = message.nodeid; }
2571
- if (message.tag != null) { n.tag = message.tag; }
2572
- if (message.url != null) { n.url = message.url; }
2573
- if (message.username != null) { n.username = message.username; }
2574
- if (typeof message.maxtime === 'number') { n.maxtime = message.maxtime; }
2575
- addNotification(n);
2576
- } else if (message.type === 'ps') {
2577
- showDeskToolsProcesses(message);
2578
- } else if (message.type === 'services') {
2579
- showDeskToolsServices(message);
2580
- } else if ((message.type === 'getclip') && (currentNode != null) && (currentNode._id == message.nodeid)) {
2581
- if ((message.tag == 1) && (xxdialogTag === 'clipboard')) {
2582
- Q('d2clipText').value = message.data; // Put remote clipboard data into dialog box
2583
- } else if (message.tag === 2) {
2584
- if (navigator.clipboard != null) { navigator.clipboard.writeText(message.data).then(function() { }).catch(function(err) { console.log(err); }) } // Put remote clipboard data into our clipboard
2585
- }
2586
- } else if ((message.type === 'setclip') && (xxdialogTag === 'clipboard') && (currentNode != null) && (currentNode._id == message.nodeid)) {
2587
- // Display success/fail on the clipboard dialog box.
2588
- QH('dlgClipStatus', message.success ? '<span style=color:green>' + "Success" + '</span>' : '<span style=color:red>' + "Failed" + '</span>')
2589
- setTimeout(function () { try { QH('dlgClipStatus', ''); } catch (ex) { } }, 2000);
2590
- } else if ((message.type === 'userSessions') && (currentNode != null) && (currentNode._id === message.nodeid) && (desktop == null)) {
2591
- // Got list of user sessions
2592
- var userSessions = [];
2593
- if (message.data != null) { for (var i in message.data) { if ((message.data[i].State == 'Active') || (message.data[i].State == 'Connected') || (message.data[i].StationName == 'Console') || (debugmode == 3)) { userSessions.push(message.data[i]); } } }
2594
- if (userSessions.length === 0) { connectDesktop(null, 1, null, message.tag); } // No active sessions, do a normal connection.
2595
- else if (userSessions.length === 1) { connectDesktop(null, 1, userSessions[0].SessionId, message.tag); } // One active session, connect to it
2596
- else {
2597
- var x = '';
2598
- for (var i in userSessions) {
2599
- x += '<div style="text-align:left;cursor:pointer;background-color:gray;margin:5px;padding:5px;border-radius:5px" onclick=connectDesktop(event,1,' + userSessions[i].SessionId + ',' + message.tag + ')>' + userSessions[i].State + (userSessions[i].StationName ? (', ' + userSessions[i].StationName) : '');
2600
- if (userSessions[i].Username) { if (userSessions[i].Domain) { x += ' - ' + userSessions[i].Domain + '/' + userSessions[i].Username; } else { x += ' - ' + userSessions[i].Username; } }
2601
- x += '</div>';
2602
- }
2603
- QH('p11DeskSessionSelector', x);
2604
- QV('p11DeskSessionSelector', true);
2605
- }
2606
- } else if (message.type === 'psinfo') {
2607
- if (xxdialogTag === ('ps|' + message.nodeid + '|' + message.pid)) {
2608
- var x = '<div style=max-height:200px;overflow-y:auto>';
2609
- //x += addHtmlValue4("Process ID", message.pid);
2610
- if ((typeof message.value == 'object') && (Object.keys(message.value).length > 0)) {
2611
- if (message.value.processName) { x += '<div style=padding:4px><div style=padding-bottom:4px>' + "Process Name" + '</div><div style=word-wrap:break-word;padding-left:6px><b>' + message.value.processName + '</b></div></div>'; }
2612
- if (message.value.machineName) { x += addHtmlValue5("Machine Name", message.value.machineName); }
2613
- if (message.value.cmd) { x += '<div style=padding:4px><div style=padding-bottom:4px>' + "Command Line" + '</div><div style=word-wrap:break-word;padding-left:6px><b>' + message.value.cmd + '</b></div></div>'; }
2614
- if (message.value.mainWindowTitle) { x += '<div style=padding:4px><div style=padding-bottom:4px>' + "Window Title" + '</div><div style=word-wrap:break-word;padding-left:6px><b>' + message.value.mainWindowTitle + '</b></div></div>'; }
2615
- if (message.value.processUser) { x += addHtmlValue5("User", message.value.processUser); }
2616
- if (message.value.processDomain) { x += addHtmlValue5("Domain", message.value.processDomain); }
2617
- if (message.value.startTime) { x += addHtmlValue5("Start Time", message.value.startTime); }
2618
- x += '<hr />';
2619
- if (message.value.PriorityBoostEnabled) { x += addHtmlValue5("Priority Boost", message.value.PriorityBoostEnabled?"Enabled":"Disabled"); }
2620
- if (message.value.sessionId) { x += addHtmlValue5("Session Id", message.value.sessionId); }
2621
- if (message.value.handleCount) { x += addHtmlValue5("Handle Count", message.value.handleCount); }
2622
- if (message.value.privilegedProcessorTime) { x += addHtmlValue5("Privileged Processor Time", format("{0} seconds", message.value.privilegedProcessorTime)); }
2623
- if (message.value.totalProcessorTime) { x += addHtmlValue5("Total Processor Time", format("{0} seconds", message.value.totalProcessorTime)); }
2624
- if (message.value.userProcessorTime) { x += addHtmlValue5("User Processor Time", format("{0} seconds", message.value.userProcessorTime)); }
2625
- if (message.value.nonpagedSystemMemorySize) { x += addHtmlValue5("Non Paged Memory", getNiceSize2(message.value.nonpagedSystemMemorySize)); }
2626
- if (message.value.pagedMemorySize) { x += addHtmlValue5("Paged Memory", getNiceSize2(message.value.pagedMemorySize)); }
2627
- if (message.value.privateMemorySize) { x += addHtmlValue5("Private Memory", getNiceSize2(message.value.privateMemorySize)); }
2628
- if (message.value.virtualMemorySize) { x += addHtmlValue5("Virtual Memory", getNiceSize2(message.value.virtualMemorySize)); }
2629
- if (message.value.workingSet) { x += addHtmlValue5("Working Set", getNiceSize2(message.value.workingSet)); }
2630
- if (message.value.peakWorkingSet) { x += addHtmlValue5("Peak Working Set", getNiceSize2(message.value.peakWorkingSet)); }
2631
- if (message.value.peakPagedMemorySize) { x += addHtmlValue5("Peak Paged Memory", getNiceSize2(message.value.peakPagedMemorySize)); }
2632
- if (message.value.peakVirtualMemorySize) { x += addHtmlValue5("Peak Virtual Memory", getNiceSize2(message.value.peakVirtualMemorySize)); }
2633
- } else {
2634
- x += "No information provided";
2635
- }
2636
- x += '</div>';
2637
- QH('id_dialogOptions', x);
2638
- }
2639
- }
2640
- }
2641
- } else {
2642
- if (message.type === 'notify') { // This is a notification message.
2643
- var n = { text: message.value, title: message.title, icon: message.icon, titleid: message.titleid, msgid: message.msgid, args: message.args };
2644
- if (message.id != null) { n.id = message.id; }
2645
- if (message.tag != null) { n.tag = message.tag; }
2646
- if (message.url != null) { n.url = message.url; }
2647
- if (message.username != null) { n.username = message.username; }
2648
- if (typeof message.maxtime == 'number') { n.maxtime = message.maxtime; }
2649
- addNotification(n);
2650
- }
2651
- }
2652
- break;
2653
- }
2654
- case 'getnetworkinfo': {
2655
- if (currentNode._id != message.nodeid) return;
2656
- updateDeviceDetails(getNodeFromId(message.nodeid), null, message);
2657
- if ((xxdialogMode == 2) && (xxdialogTag == 'if' + message.nodeid)) {
2658
- var x = '<div class=dialogText>';
2659
- if (currentNode.lastconnect) { x += addHtmlValue2("Last agent connection", printDateTime(new Date(currentNode.lastconnect))); }
2660
- if (currentNode.lastaddr) {
2661
- var splitip = currentNode.lastaddr.split(':');
2662
- if (splitip.length > 2) {
2663
- // IPv6
2664
- x += addHtmlValue2("Last agent address", currentNode.lastaddr + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(currentNode.lastaddr) + '") width=10 height=10>');
2665
- } else {
2666
- // IPv4
2667
- if (isPrivateIP(currentNode.lastaddr)) {
2668
- x += addHtmlValue2("Last agent address", splitip[0] + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(splitip[0]) + '") width=10 height=10>');
2669
- } else {
2670
- x += addHtmlValue2("Last agent address", '<a href="https://iplocation.com/?ip=' + splitip[0] + '" rel="noreferrer noopener" target="MeshIPLoopup">' + splitip[0] + '</a> <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(splitip[0]) + '") width=10 height=10>');
2671
- }
2672
- }
2673
- }
2674
- if (message.updateTime != null) { x += addHtmlValue2("Last interfaces update", printDateTime(new Date(message.updateTime))); }
2675
-
2676
- if (message.netif != null) {
2677
- // Old style
2678
- for (var i in message.netif) {
2679
- var net = message.netif[i];
2680
- x += '<hr />'
2681
- if (net.name) { x += addHtmlValue2("Name", '<b>' + EscapeHtml(net.name) + '</b>'); }
2682
- if (net.desc) { x += addHtmlValue2("Description", EscapeHtml(net.desc).replace('(R)', '®').replace('(r)', '®')); }
2683
- if (net.dnssuffix) { x += addHtmlValue2("DNS suffix", EscapeHtml(net.dnssuffix) + ' <img src="images/link4.png" title="' + "Copy name to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.dnssuffix) + '") width=10 height=10>'); }
2684
- if (net.mac) { x += addHtmlValue2("MAC address", '<a href="https://dnslytics.com/mac-address-lookup/' + net.mac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.mac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.mac.toLowerCase()) + '") width=10 height=10>'); }
2685
- if (net.v4addr) { x += addHtmlValue2("IPv4 address", EscapeHtml(net.v4addr) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4addr) + '") width=10 height=10>'); }
2686
- if (net.v4mask) { x += addHtmlValue2("IPv4 mask", EscapeHtml(net.v4mask) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4mask) + '") width=10 height=10>'); }
2687
- if (net.v4gateway) { x += addHtmlValue2("IPv4 gateway", EscapeHtml(net.v4gateway) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4gateway) + '") width=10 height=10>'); }
2688
- if (net.gatewaymac) { x += addHtmlValue2("Gateway MAC", '<a href="https://dnslytics.com/mac-address-lookup/' + net.gatewaymac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.gatewaymac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.gatewaymac.toLowerCase()) + '") width=10 height=10>'); }
2689
- }
2690
- } else if (message.netif2 != null) {
2691
- // New style
2692
- for (var i in message.netif2) {
2693
- var net = message.netif2[i];
2694
- if ((Array.isArray(net) == false) || (net.length < 1) || (net[0] == null) || ((typeof net[0].mac == 'string') && (net[0].mac.startsWith('00:00:00:00')))) continue;
2695
- x += '<hr />'
2696
- x += addHtmlValue2("Name", '<b>' + EscapeHtml(i) + '</b>');
2697
- if (typeof net[0].mac == 'string') { x += addHtmlValue2("MAC address", '<a href="https://dnslytics.com/mac-address-lookup/' + net[0].mac.split(':').join('').substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net[0].mac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net[0].mac.toLowerCase()) + '") width=10 height=10>'); }
2698
- if (net[0].fqdn) { x += addHtmlValue2("FQDN", net[0].fqdn); }
2699
- for (var j = 0; j < net.length; j++) {
2700
- var netif = net[j];
2701
- if (netif.family == 'IPv6') {
2702
- if (netif.address) { x += addHtmlValue2("IPv6 address", EscapeHtml(netif.address) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(netif.address) + '") width=10 height=10>'); }
2703
- if (netif.netmask) { x += addHtmlValue2("IPv6 mask", EscapeHtml(netif.netmask) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(netif.netmask) + '") width=10 height=10>'); }
2704
- if (netif.gateway) { x += addHtmlValue2("IPv6 gateway", EscapeHtml(netif.gateway) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(netif.gateway) + '") width=10 height=10>'); }
2705
- } else if (netif.family == 'IPv4') {
2706
- if (netif.address) { x += addHtmlValue2("IPv4 address", EscapeHtml(netif.address) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(netif.address) + '") width=10 height=10>'); }
2707
- if (netif.netmask) { x += addHtmlValue2("IPv4 mask", EscapeHtml(netif.netmask) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(netif.netmask) + '") width=10 height=10>'); }
2708
- if (netif.gateway) { x += addHtmlValue2("IPv4 gateway", EscapeHtml(netif.gateway) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(netif.gateway) + '") width=10 height=10>'); }
2709
- }
2710
- }
2711
- }
2712
- } else {
2713
- x += '<hr />'
2714
- x += "No network interface information available for this device.";
2715
- }
2716
- x += '</div>';
2717
- QH('d2netinfo', x);
2718
- }
2719
- break;
2720
- }
2721
- case 'serverversion': {
2722
- if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerUpdate')) {
2723
- var x = '<div class=dialogText>';
2724
- if (!message.tags.current) { message.tags.current = "Unknown"; }
2725
- if (!message.tags.stable) { message.tags.stable = "Unknown"; }
2726
- if (!message.tags.latest) { message.tags.latest = "Unknown"; }
2727
- x += addHtmlValue2("Current Version", '<b>' + EscapeHtml(message.tags.current) + '</b>');
2728
- x += '<hr />';
2729
- x += addHtmlValue2('<label><input id=d2updateCheck1 type=checkbox onclick=server_showVersionDlgUpdate()' + (((message.tags.stable == "Unknown") || (message.tags.current == message.tags.stable) || ((features & 2048) == 0))?' disabled':'') + ' /> ' + "Stable Version" + '</label>', '<b>' + EscapeHtml(message.tags.stable) + '</b>');
2730
- x += addHtmlValue2('<label><input id=d2updateCheck2 type=checkbox onclick=server_showVersionDlgUpdate()' + (((message.tags.latest == "Unknown") || (message.tags.current == message.tags.latest) || ((features & 2048) == 0))?' disabled':'') + ' /> ' + "Latest Version" + '</label>', '<b>' + EscapeHtml(message.tags.latest) + '</b>');
2731
- x += '</div>';
2732
- if (((message.tags.current == message.tags.latest) && (message.tags.current == message.tags.stable)) || ((features & 2048) == 0)) {
2733
- setDialogMode(2, "MeshCentral Version", 1, null, x);
2734
- } else {
2735
- x += '<hr />' + "Check and click OK to start server self-update.";
2736
- setDialogMode(2, "MeshCentral Version", 3, server_showVersionDlgEx, x, message.tags);
2737
- server_showVersionDlgUpdate();
2738
- }
2739
- }
2740
- break;
2741
- }
2742
- case 'servererrors': {
2743
- if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerErrors')) {
2744
- if (message.data == null) {
2745
- setDialogMode(2, "MeshCentral Server Errors", 1, null, "Server has no error log.");
2746
- } else {
2747
- var x = '<div class="dialogText dialogTextLog"><pre id=d2ServerErrorsLogPre>' + EscapeHtml(message.data) + '</pre></div>';
2748
- x += '<br /><div style=float:right><img src=images/link4.png height=10 width=10 title="' + "Download error log" + '" style=cursor:pointer onclick=d2CopyServerErrorsToClip()></div>';
2749
- x += '<div><label><input id=d2clearErrorsCheck type=checkbox onclick=server_showErrorsDlgUpdate() /> ' + "Check and click OK to clear error log." + '</label></div>';
2750
- setDialogMode(2, "MeshCentral Server Errors", 3, server_showErrorsDlgEx, x);
2751
- server_showErrorsDlgUpdate();
2752
- }
2753
- }
2754
- break;
2755
- }
2756
- case 'serverconsole': {
2757
- p15consoleReceive('serverconsole', message.value);
2758
- break;
2759
- }
2760
- case 'events': {
2761
- if ((message.nodeid != null) && (currentNode != null) && (message.nodeid == currentNode._id)) {
2762
- currentDeviceEvents = message.events;
2763
- mainUpdate(1024);
2764
- } else if ((message.userid != null) && (currentUser != null) && (message.userid == currentUser._id)) {
2765
- currentUserEvents = message.events;
2766
- mainUpdate(2048);
2767
- } else {
2768
- events = message.events;
2769
- mainUpdate(32);
2770
- }
2771
- break;
2772
- }
2773
- case 'recordings': {
2774
- p52recordings = message.events;
2775
- if (message.error != null) { p52recordings = message.error; }
2776
- updateRecordings();
2777
- break;
2778
- }
2779
- case 'getcookie': {
2780
- if (message.tag == 'MCRouter') {
2781
- var servername = serverinfo.name;
2782
- if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
2783
- var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
2784
- var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
2785
- var url = 'mcrouter://' + servername + portStr + domainUrl + 'control.ashx?c=' + authCookie + '&t=' + serverinfo.tlshash + '&l={{{lang}}}' + (urlargs.key?('&key=' + urlargs.key):'');
2786
- if (message.nodeid != null) { url += ('&nodeid=' + message.nodeid); }
2787
- if (message.tcpport != null) { url += ('&protocol=1&remoteport=' + message.tcpport); }
2788
- if (message.localRelay) { url += '&local=1'; }
2789
- if (message.localport) { url += '&localport=' + message.localport; }
2790
- if (message.name != null) { url += ('&name=' + encodeURIComponentEx(message.name)); }
2791
- if (message.ip != null) { url += ('&remoteip=' + message.ip); }
2792
- url += ('&appid=' + message.protocol + '&autoexit=1'); // Protocol: 0 = Custom, 1 = HTTP, 2 = HTTPS, 3 = RDP, 4 = PuTTY, 5 = WinSCP, 6 = MCRDesktop, 7 = MCRFiles
2793
- //console.log(url);
2794
- downloadFile(url, '');
2795
- } else if (message.tag == 'novnc') {
2796
- var vncurl = window.location.origin + domainUrl + 'novnc/vnc.html?ws=wss%3A%2F%2F' + window.location.host + encodeURIComponentEx(domainUrl) + (message.localRelay?'local':'mesh') + 'relay.ashx%3Fauth%3D' + message.cookie + '&show_dot=1' + (urlargs.key?('&key=' + urlargs.key):'') + '&l={{{lang}}}';
2797
- var node = getNodeFromId(message.nodeid);
2798
- if (node != null) { vncurl += '&name=' + encodeURIComponentEx(node.name); }
2799
- safeNewWindow(vncurl, 'mcnovnc/' + message.nodeid);
2800
- } else if (message.tag == 'mstsc') {
2801
- var rdpurl = window.location.origin + domainUrl + 'mstsc.html?ws=' + message.cookie + (urlargs.key?('&key=' + urlargs.key):'');
2802
- var node = getNodeFromId(message.nodeid);
2803
- if (node != null) { rdpurl += '&name=' + encodeURIComponentEx(node.name); }
2804
- if (message.localRelay) { rdpurl += '&local=1'; }
2805
- safeNewWindow(rdpurl, 'mcmstsc/' + message.nodeid);
2806
- } else if (message.tag == 'ssh') {
2807
- var sshurl = window.location.origin + domainUrl + 'ssh.html?ws=' + message.cookie + (urlargs.key?('&key=' + urlargs.key):'');
2808
- var node = getNodeFromId(message.nodeid);
2809
- if (node != null) { sshurl += '&name=' + encodeURIComponentEx(node.name); }
2810
- if (message.localRelay) { sshurl += '&local=1'; }
2811
- safeNewWindow(sshurl, 'mcssh/' + message.nodeid);
2812
- }
2813
- break;
2814
- }
2815
- case 'getNotes': {
2816
- var n = Q('d2devNotes');
2817
- if (n && (message.id == decodeURIComponent(n.attributes['noteid'].value))) {
2818
- if (message.notes) { QH('d2devNotes', decodeURIComponent(message.notes)); } else { QH('d2devNotes', ''); }
2819
- var ro = (n.attributes['ro'].value == 'true');
2820
- if (ro == false) { // If we have permissions, set read/write on this note.
2821
- n.removeAttribute('readonly');
2822
- QE('idx_dlgOkButton', true);
2823
- QV('idx_dlgOkButton', true);
2824
- focusTextBox('d2devNotes');
2825
- }
2826
- }
2827
- break;
2828
- }
2829
- case 'otpauth-request': {
2830
- if ((xxdialogMode == 2) && (xxdialogTag == 'otpauth-request')) {
2831
- if (message.err != null) {
2832
- var otpauthErrors = [ '', "2FA is locked", "Backup codes are locked", "Login token in use", "OTP 2FA not allowed", "Account is locked", "Unable to load OTPLIB" ];
2833
- if ((message.err > 0) && (message.err < otpauthErrors.length)) { QH('d2optinfo', otpauthErrors[message.err]); } else { QH('d2optinfo', format("Error #{0}", message.err)); }
2834
- } else {
2835
- var secret = message.secret;
2836
- if (secret.length == 52) { secret = secret.split(/(.............)/).filter(Boolean).join(' '); }
2837
- else if (secret.length == 32) { secret = secret.split(/(....)/).filter(Boolean).join(' '); secret = secret.substring(0, 20) + '<br/>' + secret.substring(20) }
2838
- QH('d2optinfo', '<table style=width:380px><tr><td style=vertical-align:top>' + format("Install <a href=\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\" rel=\"noreferrer noopener\" target=_blank>Google Authenticator</a> or a compatible application and scan the barcode, use <a href=\"{0}\" rel=\"noreferrer noopener\" target=_blank>this link</a> or enter the secret. Then, enter the current 6 digit token below to activate 2-Step login.", message.url) + '<br /><br />' + "Secret" + '<br /><tt id=d2optsecret secret="' + message.secret + '" style=font-size:12px>' + secret + '</tt><br /><br /></td><td style=width:1px;vertical-align:top><a href="' + message.url + '" rel="noreferrer noopener" target=_blank><div id="qrcode"></div></a></td><tr><td colspan=2 style="text-align:center;border-top:1px solid black"><br />' + "Enter the token here for 2-step login:" + ' <input type=text autocomplete="one-time-code" inputmode="numeric" pattern="[0-9]*" onkeypress="return (event.keyCode == 8) || (event.charCode >= 48 && event.charCode <= 57)" onkeyup=account_addOtpCheck(event) onkeydown=account_addOtpCheck() maxlength=6 id=d2otpauthinput type=text></td></table>');
2839
- new QRCode(Q('qrcode'), { text: message.url, width: 128, height: 128, colorDark: '#000000', colorLight: '#EEE', correctLevel: QRCode.CorrectLevel.H });
2840
- QV('idx_dlgOkButton', true);
2841
- QE('idx_dlgOkButton', false);
2842
- Q('d2otpauthinput').focus();
2843
- }
2844
- }
2845
- break;
2846
- }
2847
- case 'otpauth-setup': {
2848
- if (xxdialogMode) return;
2849
- setDialogMode(2, "Authenticator App", 1, null, message.success ? ('<b style=color:green>' + "Authenticator app activation successful." + '</b> ' + "You will now need a valid token to login again.") : ('<b style=color:red>' + "2-step login activation failed." + '</b> ' + "Clear the secret from the application and try again. You only have a few minutes to enter the proper code."));
2850
- break;
2851
- }
2852
- case 'otpauth-clear': {
2853
- if (xxdialogMode) return;
2854
- setDialogMode(2, "Authenticator App", 1, null, message.success ? ('<b>' + "Authenticator application removed." + '</b> ' + "You can reactivate this feature at any time.") : ('<b style=color:red>' + "2-step login activation removal failed." + '</b> ' + "Try again."));
2855
- break;
2856
- }
2857
- case 'otpauth-getpasswords': {
2858
- if (xxdialogMode) return;
2859
- var x = "One time tokens can be used as secondary authentication. Generate a set, print them and keep them in a safe place.";
2860
- x += '<div style="border-radius:6px;border: 2px dashed #888;width:100%;margin-top:8px"><div style="padding:8px;font-family:Arial, Helvetica, sans-serif;font-size:20px;font-weight:bold"><table class=selecttext style=width:100%;text-align:center>';
2861
- if (message.passwords) {
2862
- var j = 0, clipb = '';
2863
- for (var i in message.passwords) {
2864
- if (++j % 2) { x += '<tr>'; }
2865
- var p = '' + message.passwords[i].p;
2866
- while (p.length < 8) { p = '0' + p; }
2867
- if (message.passwords[i].u === true) {
2868
- x += '<td>' + p.substring(0, 4) + ' ' + p.substring(4);
2869
- if (clipb != '') { clipb += ' '; }
2870
- clipb += p;
2871
- } else {
2872
- x += '<td><strike style=color:#BBB>' + p.substring(0, 4) + ' ' + p.substring(4); + '</strike>';
2873
- }
2874
- }
2875
- } else {
2876
- x += '<tr><td>' + "No Active Tokens";
2877
- }
2878
- x += '</table></div></div><br />';
2879
- x += '<div><input type=button value=' + "Close" + ' onclick=setDialogMode(0) style=float:right></input>';
2880
- x += '<input type=button value="' + "Generate New Tokens" + '" onclick="account_manageOtp(1);"></input>';
2881
- if (message.passwords != null) {
2882
- x += '<input type=button value="' + "Clear Tokens" + '" onclick="account_manageOtp(2);"></input>';
2883
- x += ' <img src=images/link4.png height=10 width=10 title="' + "Copy valid codes to clipboard" + '" style=cursor:pointer onclick=copyTextToClip2("' + encodeURIComponentEx(clipb) + '")>';
2884
- }
2885
- x += '</div><br />';
2886
- setDialogMode(2, "Manage Backup Codes", 8, null, x, 'otpauth-manage');
2887
- break;
2888
- }
2889
- case 'otp-hkey-get': {
2890
- if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
2891
- var start = '<div style="border-radius:6px;border:2px solid #CCC;background-color:#BBB;width:100%;box-sizing:border-box;margin-bottom:6px"><div style="margin:3px;font-family:Arial, Helvetica, sans-serif;font-size:16px;font-weight:bold"><table style=width:100%;text-align:left>';
2892
- var end = '</table></div></div>';
2893
- var x = "<a href=\"https://www.yubico.com/\" rel=\"noreferrer noopener\" target=\"_blank\">Hardware keys</a> are used as secondary login authentication.";
2894
- x += '<div style="max-height:150px;overflow-y:auto;overflow-x:hidden;margin-top:6px;margin-bottom:6px">';
2895
- if (message.keys && message.keys.length > 0) {
2896
- for (var i in message.keys) {
2897
- var key = message.keys[i], type = (key.type == 2)?'OTP':'WebAuthn';
2898
- x += start + '<tr style=margin:5px><td style=width:30px><img width=24 height=18 src="images/hardware-key-' + type + '-24.png" style=margin-top:4px><td style=width:250px>' + key.name + '<td><input type=button value="' + "Remove" + '" onclick=account_removehkey(' + key.i + ')></input>' + end;
2899
- }
2900
- } else {
2901
- x += start + '<tr style=text-align:center><td>' + "No Keys Configured" + end;
2902
- }
2903
- x += '</div>';
2904
- x += '<div><input type=button value="' + "Close" + '" onclick=setDialogMode(0) style=float:right></input>';
2905
- var hkeycount = (typeof userinfo.otphkeys == 'number') ? userinfo.otphkeys : 0;
2906
- if ((typeof serverinfo.maxfidokeys != 'number') || (serverinfo.maxfidokeys > hkeycount)) { // Check if we we reached maximum hardware keys
2907
- if ((features & 0x00020000) != 0) { x += '<input id=d2addkey3 type=button value="' + "Add Key" + '" onclick="account_addhkey(3);"></input>'; }
2908
- if ((features & 0x00004000) != 0) { x += '<input id=d2addkey2 type=button value="' + "Add YubiKey® OTP" + '" onclick="account_addhkey(2);"></input>'; }
2909
- } else {
2910
- x += "Maximum keys reached.";
2911
- }
2912
- x += '</div><br />';
2913
- setDialogMode(2, "Manage Security Keys", 8, null, x, 'otpauth-hardware-manage');
2914
- if (u2fSupported() == false) { QE('d2addkey1', false); }
2915
- break;
2916
- }
2917
- case 'otp-hkey-yubikey-add': {
2918
- if (message.result) {
2919
- meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
2920
- } else {
2921
- setDialogMode(2, "Add Security Key", 1, null, '<br />' + "Error, Unable to add key." + '<br /><br />');
2922
- }
2923
- break;
2924
- }
2925
- case 'otp-hkey-setup-response': {
2926
- if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
2927
- if (message.result == true) {
2928
- meshserver.send({ action: 'otp-hkey-get' }); // Success, ask for the full list of keys.
2929
- } else {
2930
- setDialogMode(2, "Add Security Key", 1, null, '<br />' + "ERROR: Unable to add key." + '<br /><br />', 'otpauth-hardware-manage');
2931
- }
2932
- break;
2933
- }
2934
- case 'webauthn-startregister': {
2935
- if (xxdialogMode && (xxdialogTag != 'otpauth-hardware-manage')) return;
2936
- var x = "Press the key button now." + '<br /><br /><div style=width:100%;text-align:center><img width=120 height=117 src="images/hardware-keypress-120.png" /></div><input id=dp1keyname style=display:none value=' + message.name + ' />';
2937
- setDialogMode(2, "Add Security Key", 2, null, x);
2938
-
2939
- var publicKey = message.request;
2940
- message.request.challenge = Uint8Array.from(atob(message.request.challenge), function (c) { return c.charCodeAt(0) })
2941
- message.request.user.id = Uint8Array.from(atob(message.request.user.id), function (c) { return c.charCodeAt(0) })
2942
- navigator.credentials.create({ publicKey: publicKey }).then(function(newCredentialInfo) {
2943
- // Public key credential
2944
- meshserver.send({ action: 'webauthn-endregister', response: { rawId: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.rawId))), response: { attestationObject: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.attestationObject))), clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(newCredentialInfo.response.clientDataJSON))) }, type: newCredentialInfo.type } });
2945
- setDialogMode(0);
2946
- }, function(error) {
2947
- // Error
2948
- console.log("ERROR: " + error);
2949
- setDialogMode(2, "Add Security Key", 1, null, "ERROR: " + error);
2950
- });
2951
- break;
2952
- }
2953
- case 'verifyPhone': {
2954
- if (xxdialogMode && (xxdialogTag != 'verifyPhone')) return;
2955
- var x = '<table><tr><td><img src="images/phone80.png" style=padding:8px>';
2956
- x += '<td>' + "Check your phone and enter the verification code.";
2957
- x += '<br /><br /><div style=width:100%;text-align:center>' + "Verification code:" + ' <input type=tel pattern="[0-9]" inputmode="number" maxlength=6 id=d2phoneCodeInput onKeyUp=account_managePhoneCodeValidate() onkeypress="if (event.key==\'Enter\') account_managePhoneCodeValidate(1)"></div></table>';
2958
- setDialogMode(2, "Phone Notifications", 3, account_managePhoneConfirm, x, message.cookie);
2959
- Q('d2phoneCodeInput').focus();
2960
- account_managePhoneCodeValidate();
2961
- break;
2962
- }
2963
- case 'verifyMessaging': {
2964
- if (xxdialogMode && (xxdialogTag != 'verifyMessaging')) return;
2965
- var x = '<table><tr><td><img src="images/messaging40.png" style=padding:8px>';
2966
- x += '<td>' + "Check your messaging application and enter the verification code.";
2967
- x += '<br /><br /><div style=width:100%;text-align:center>' + "Verification code:" + ' <input type=tel pattern="[0-9]" inputmode="number" maxlength=6 id=d2phoneCodeInput onKeyUp=account_managePhoneCodeValidate() onkeypress="if (event.key==\'Enter\') account_managePhoneCodeValidate(1)"></div></table>';
2968
- setDialogMode(2, "Messaging Notifications", 3, account_manageMessagingConfirm, x, message.cookie);
2969
- Q('d2phoneCodeInput').focus();
2970
- account_managePhoneCodeValidate();
2971
- break;
2972
- }
2973
- case 'fileoperation': {
2974
- // View the file in the dialog box
2975
- var p5editSaveBack = function(b, tag) {
2976
- var data;
2977
- if (d4EditEncodingVal == 1) {
2978
- data = encode_utf8(Q('d4editorarea').value); // UTF8 encoding
2979
- } else {
2980
- data = Q('d4editorarea').value; // RAW encoding
2981
- }
2982
- meshserver.send({ action: 'fileoperation', fileop: 'set', path: tag.path, file: tag.file, data: btoa(data) });
2983
- }
2984
- setDialogMode(4, EscapeHtml(message.file), 3, p5editSaveBack, null, message);
2985
- QS('dialog').width = 'auto';
2986
- QS('dialog').bottom = '80px';
2987
- QS('dialog').top = QS('dialog').left = QS('dialog').right = '100px';
2988
- if (d4EditEncodingVal == 1) {
2989
- Q('d4editorarea').value = decode_utf8(atob(message.data)); // UTF8 Encoding
2990
- } else {
2991
- Q('d4editorarea').value = atob(message.data); // RAW Encoding
2992
- }
2993
- break;
2994
- }
2995
- case 'event': {
2996
- if (!message.event.nolog) {
2997
- if (currentNode && (message.event.nodeid == currentNode._id) && (currentDeviceEvents != null)) {
2998
- // If this event has a nodeid and we are looking at this node, update the log in real time.
2999
- currentDeviceEvents.unshift(message.event);
3000
- var eventLimit = parseInt(p16limitdropdown.value);
3001
- while (currentDeviceEvents.length > eventLimit) { currentDeviceEvents.pop(); } // Remove element(s) at the end
3002
- mainUpdate(1024);
3003
- }
3004
-
3005
- if (currentUser && (message.event.userid == currentUser._id)) {
3006
- // If this event has a userid and we are looking at this user, update the log in real time.
3007
- currentUserEvents.unshift(message.event);
3008
- var eventLimit = parseInt(p31limitdropdown.value);
3009
- while (currentUserEvents.length > eventLimit) { currentUserEvents.pop(); } // Remove element(s) at the end
3010
- mainUpdate(2048);
3011
- }
3012
-
3013
- // Add this event to the main events log.
3014
- events.unshift(message.event);
3015
- var eventLimit = parseInt(p3limitdropdown.value);
3016
- while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
3017
- mainUpdate(32);
3018
- }
3019
- if (message.event.noact) break; // Take no action on this event
3020
-
3021
- switch (message.event.action) {
3022
- case 'serverinfochange': {
3023
- if (message.event.lock2factor != null) { serverinfo.lock2factor = message.event.lock2factor; updateSelf(); updateSiteAdmin(); }
3024
- break;
3025
- }
3026
- case 'deviceShareUpdate': {
3027
- if (message.event.nodeid != deviceSharesReq) break;
3028
- deviceSharesNode = message.event.nodeid;
3029
- deviceShares = message.event.deviceShares;
3030
- if (currentNode._id == deviceSharesNode) { gotoDevice(currentNode._id, xxcurrentView, true); }
3031
- break;
3032
- }
3033
- case 'agentlog': {
3034
- if (message.event.msgid == 98) {
3035
- // This is a agent help request, popup a notification.
3036
- if (GetNodeRights(message.event.nodeid) > 0) {
3037
- var n = getNodeFromId(message.event.nodeid);
3038
- addNotification({ text: format("Help requested from {0}: {1}", message.event.msgArgs[0], message.event.msgArgs[1]), title: n.name, icon: n.icon, nodeid: message.event.nodeid });
3039
- }
3040
- }
3041
- break;
3042
- }
3043
- case 'recording': {
3044
- if ((p52recordings != null) && (typeof p52recordings == 'object')) { p52recordings.unshift(message.event); message.event.present = 1; updateRecordings(); }
3045
- break;
3046
- }
3047
- case 'userWebState': {
3048
- // New user web state, update the web page as needed
3049
- try {
3050
- if (localStorage != null) {
3051
- // TODO: The problem with this "old" values is that if changed from a different tab, the old and new values will be the same.
3052
- // So comparing against these values is not a good idea.
3053
- var oldShowRealNames = localStorage.getItem('showRealNames');
3054
- var oldUiMode = localStorage.getItem('uiMode');
3055
- var oldSort = localStorage.getItem('sort');
3056
- var oldLoctag = localStorage.getItem('loctag');
3057
- var oldNightMode = localStorage.getItem('nightMode');
3058
- var oldFooterBar = localStorage.getItem('footerBar');
3059
-
3060
- var webstate = JSON.parse(message.event.state);
3061
- for (var i in webstate) { localStorage.setItem(i, webstate[i]); }
3062
-
3063
- // Update the web page
3064
- //if ((webstate.deskAspectRatio != null) && (webstate.deskAspectRatio != deskAspectRatio)) { deskAspectRatio = webstate.deskAspectRatio; deskAdjust(); }
3065
- if ((webstate.showRealNames != null) && (webstate.showRealNames != oldShowRealNames)) { showRealNames = Q('RealNameCheckBox').checked = (webstate.showRealNames == '1'); mainUpdate(6); }
3066
- if ((webstate.uiMode != null) && (webstate.uiMode != oldUiMode)) { userInterfaceSelectMenu(parseInt(webstate.uiMode)); }
3067
- if ((webstate.sort != null) && (webstate.sort != oldSort)) { document.getElementById('sortselect').selectedIndex = sort = parseInt(webstate.sort); mainUpdate(6); }
3068
- if ((webstate.loctag != null) && (webstate.loctag != oldLoctag)) { if (webstate.loctag != null) { args.locale = webstate.loctag; } else { delete args.locale; } mainUpdate(0xFFFFFFFF); }
3069
- if ((webstate.nightMode != null) && (webstate.nightMode != oldNightMode)) { putstore('nightMode', webstate.nightMode); setNightMode(); }
3070
- if ((webstate.footerBar != null) && (webstate.footerBar != oldFooterBar)) { footerBar = (webstate.footerBar == '1'); QS('container')['grid-template-rows'] = null; QS('container')['-ms-grid-rows'] = null; adjustPanels(); }
3071
- if ((webstate.stars != null) && (webstate.stars != JSON.stringify(stars))) {
3072
- stars = JSON.parse(webstate.stars);
3073
- if (Q('DevFilterSelect').value == 3) { mainUpdate(5); } else { mainUpdate(4); }
3074
- if (currentNode) { refreshDevice(currentNode._id); }
3075
- }
3076
- if (webstate.deskKeyShortcuts != null) {
3077
- // Set the user's desktop shortcut keys
3078
- deskKeyboardShortcuts = [];
3079
- var deskKeyboardShortcutsStr = webstate.deskKeyShortcuts.split(',');
3080
- for (var i in deskKeyboardShortcutsStr) { deskKeyboardShortcuts.push(parseInt(deskKeyboardShortcutsStr[i])); }
3081
- updateDeskShortcutKeys();
3082
- }
3083
- if (webstate.deskStrings != null) {
3084
- // Set the user's desktop strings
3085
- var s = null;
3086
- try { s = JSON.parse(webstate.deskStrings); } catch (ex) {}
3087
- if (Array.isArray(s)) { deskKeyboardStrings = s; updateDesktopStrings(); }
3088
- }
3089
- }
3090
- } catch (ex) {}
3091
- break;
3092
- }
3093
- case 'servertimelinestats': { addServerTimelineStats(message.event.data); break; }
3094
- case 'accountcreate':
3095
- case 'accountchange': {
3096
- // An account was created or changed
3097
- if ((typeof message.event.account != 'object') || (message.event.account == null)) { console.log(message.event); return; }
3098
- if (userinfo._id == message.event.account._id) {
3099
- var newsiteadmin = message.event.account.siteadmin?message.event.account.siteadmin:0;
3100
- var oldsiteadmin = userinfo.siteadmin?userinfo.siteadmin:0;
3101
- var newRemoveRights = message.event.account.removeRights?message.event.account.removeRights:0;
3102
- var oldRemoveRights = userinfo.removeRights?userinfo.removeRights:0;
3103
- if ((message.event.account.quota != userinfo.quota) || (((userinfo.siteadmin & 8) == 0) && ((message.event.account.siteadmin & 8) != 0))) { meshserver.send({ action: 'files' }); }
3104
- var oldgroups = userinfo.groups;
3105
- userinfo = message.event.account;
3106
- if ((oldsiteadmin != newsiteadmin) || (oldRemoveRights != newRemoveRights) || (message.event.accountImageChange == 1)) { // If the site admin permission or user image has changed...
3107
- if (message.event.accountImageChange == 1) { userinfo.accountImageRnd = Math.floor(Math.random() * 9999999999); }
3108
- updateSiteAdmin();
3109
- }
3110
- updateSelf();
3111
-
3112
- if ((userinfo.siteadmin & 2) != 0) {
3113
- // Compare our groups
3114
- var og = oldgroups ? oldgroups : [];
3115
- var ng = userinfo.groups ? userinfo.groups : [];
3116
- if (og.join(',') != ng.join(',')) {
3117
- // Our groups have changed, re-ask for a list of users.
3118
- users = wssessions = null;
3119
- meshserver.send({ action: 'users' });
3120
- meshserver.send({ action: 'wssessioncount' });
3121
- }
3122
- }
3123
-
3124
- // If our list of nodes may have changes, request the new list now.
3125
- if (message.event.nodeListChange == userinfo._id) { meshserver.send({ action: 'nodes', skip: (devicePagingState == null) ? 0 : devicePagingState.skip }); }
3126
- }
3127
- if (currentNode) { refreshDevice(currentNode._id); }
3128
- if (users == null) break;
3129
-
3130
- // Check if the account is part of our user group
3131
- if ((userinfo.groups == null) || (userinfo.groups.length == 0) || (findOne(message.event.account.groups, userinfo.groups) == true)) {
3132
- users[message.event.account._id] = message.event.account; // Part of our groups, update this user.
3133
- } else {
3134
- delete users[message.event.account._id]; // No longer part of our groups, remove this user.
3135
- }
3136
-
3137
- mainUpdate(4 | 16384);
3138
- break;
3139
- }
3140
- case 'accountremove': {
3141
- // An account was removed
3142
- if (users == null) break;
3143
- delete users[message.event.userid];
3144
- mainUpdate(16384);
3145
- break;
3146
- }
3147
- case 'createusergroup':
3148
- case 'usergroupchange': {
3149
- // User group changed
3150
- if (usergroups == null) { usergroups = {}; }
3151
- var ugroup = usergroups[message.event.ugrpid];
3152
- if (ugroup == null) {
3153
- // This is a new user group for us
3154
- usergroups[message.event.ugrpid] = { _id: message.event.ugrpid, name: message.event.name, desc: message.event.desc, domain: message.event.domain, links: message.event.links };
3155
- } else {
3156
- // This is an existing user group
3157
- ugroup.name = message.event.name;
3158
- if (message.event.desc) { ugroup.desc = message.event.desc; } else { delete ugroup.desc; }
3159
- if (message.event.links) { ugroup.links = message.event.links; } else { delete ugroup.links; }
3160
- if (message.event.flags) { ugroup.flags = message.event.flags; } else { delete ugroup.flags; }
3161
- if (typeof message.event.consent == 'number') { ugroup.consent = message.event.consent; }
3162
- }
3163
- mainUpdate(4096 + 8192 + 16384);
3164
-
3165
- // Group update, refresh all our device groups and nodes. TODO: Optimize this to only do this when needed.
3166
- meshserver.send({ action: 'meshes' });
3167
- meshserver.send({ action: 'nodes', skip: (devicePagingState == null) ? 0 : devicePagingState.skip });
3168
- break;
3169
- }
3170
- case 'deleteusergroup': {
3171
- // User group removed
3172
- if ((usergroups != null) && (usergroups[message.event.ugrpid] != null)) {
3173
- delete usergroups[message.event.ugrpid];
3174
- var c = 0;
3175
- for (var i in usergroups) { c++; }
3176
- if (c == 0) { usergroups = null; } // If user groups is empty, set it to null.
3177
- mainUpdate(8192 + 16384);
3178
- }
3179
- break;
3180
- }
3181
- case 'createmesh': {
3182
- // A new mesh was created
3183
- if ((meshes[message.event.meshid] == null) && ((serverinfo.manageAllDeviceGroups) || (message.event.mesh.links[userinfo._id] != null))) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
3184
- meshes[message.event.meshid] = message.event.mesh;
3185
- mainUpdate(4 + 128 + 8192 + 16384);
3186
- meshserver.send({ action: 'files' });
3187
- }
3188
- break;
3189
- }
3190
- case 'meshchange': {
3191
- // Update mesh information
3192
- if (meshes[message.event.meshid] == null) {
3193
- // Check if we have any access to this device group
3194
- var add = false;
3195
- if (message.event.links[userinfo._id] != null) { add = true; }
3196
- if (userinfo.links[message.event.meshid] != null) { add = true; }
3197
- for (var i in userinfo.links) { if ((i.startsWith('ugrp/')) && (message.event.links[i] != null)) { add = true; } }
3198
-
3199
- // This is a new mesh for us
3200
- if (add) {
3201
- meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links, amt: message.event.amt, invite: message.event.invite, expireDevs: message.event.expireDevs, relayid: message.event.relayid };
3202
- meshserver.send({ action: 'nodes', skip: (devicePagingState == null) ? 0 : devicePagingState.skip }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh).
3203
- }
3204
- } else {
3205
- // This is an existing device group
3206
- if (message.event.name != null) {
3207
- meshes[message.event.meshid].name = message.event.name;
3208
- for (var i in nodes) { if (nodes[i].meshid == message.event.meshid) { nodes[i].meshnamel = message.event.name.toLowerCase(); } }
3209
- }
3210
- if (message.event.desc != null) { meshes[message.event.meshid].desc = message.event.desc; }
3211
- if (message.event.flags != null) { meshes[message.event.meshid].flags = message.event.flags; }
3212
- if (message.event.consent != null) { meshes[message.event.meshid].consent = message.event.consent; }
3213
- if (message.event.links) { meshes[message.event.meshid].links = message.event.links; }
3214
- if (message.event.amt) { meshes[message.event.meshid].amt = message.event.amt; }
3215
- if (message.event.invite != null) { meshes[message.event.meshid].invite = message.event.invite; } else { delete meshes[message.event.meshid].invite; }
3216
- if (message.event.expireDevs != null) { if (message.event.expireDevs > 0) { meshes[message.event.meshid].expireDevs = message.event.expireDevs; } else { delete meshes[message.event.meshid].expireDevs; } }
3217
- if (message.event.relayid != null) { meshes[message.event.meshid].relayid = message.event.relayid; }
3218
-
3219
- // Check if we lost rights to this mesh in this change.
3220
- if (IsMeshViewable(message.event.meshid) == false) {
3221
- if ((xxcurrentView == 20) && (currentMesh == meshes[message.event.meshid])) go(2);
3222
- delete meshes[message.event.meshid];
3223
-
3224
- // Delete all nodes in that mesh, except ones with direct links
3225
- var newnodes = [];
3226
- for (var i in nodes) { if ((nodes[i].meshid != message.event.meshid) || ((userinfo.links != null) && (userinfo.links[nodes[i]._id] != null))) { newnodes.push(nodes[i]); } }
3227
- nodes = newnodes;
3228
-
3229
- // If we are looking at a node that is no longer visible, move back to "My Devices"
3230
- if ((xxcurrentView >= 10) && (xxcurrentView < 20) && currentNode && !IsNodeViewable(currentNode)) { setDialogMode(0); go(1); }
3231
- }
3232
- }
3233
- mainUpdate(4 + 128 + 8192 + 16384);
3234
- if (currentNode && !IsNodeViewable(currentNode)) { currentNode = null; if ((xxcurrentView >= 10) && (xxcurrentView < 20)) { go(1); } }
3235
- //meshserver.send({ action: 'files' }); // TODO: Why do we need to do this??
3236
-
3237
- // If we are looking at a mesh that is now deleted, move back to "My Account"
3238
- if (xxcurrentView == 20 && currentMesh._id == message.event.meshid) { mainUpdate(4096); }
3239
- break;
3240
- }
3241
- case 'deletemesh': {
3242
- // Delete the mesh
3243
- if (meshes[message.event.meshid]) {
3244
- delete meshes[message.event.meshid];
3245
- mainUpdate(128);
3246
- meshserver.send({ action: 'files' });
3247
- }
3248
-
3249
- // Delete all nodes in that mesh
3250
- var newnodes = [];
3251
- if (nodes != null) { for (var i in nodes) { if (nodes[i].meshid != message.event.meshid) { newnodes.push(nodes[i]); } } }
3252
- nodes = newnodes;
3253
- mainUpdate(4 + 8192 + 16384);
3254
-
3255
- // If we are looking at a mesh that is now deleted, move back to "My Account"
3256
- if (xxcurrentView >= 20 && xxcurrentView < 30 && currentMesh._id == message.event.meshid) { setDialogMode(0); go(2); }
3257
- // If we are looking at a node in the deleted mesh, move back to "My Devices"
3258
- if (xxcurrentView >= 10 && xxcurrentView < 20 && currentNode && !IsNodeViewable(currentNode)) { setDialogMode(0); go(1); }
3259
- break;
3260
- }
3261
- case 'addnode': {
3262
- var node = message.event.node;
3263
- if (!meshes[node.meshid]) break; // This is a node for a mesh we don't know. Happens when we are site administrator, we get all messages.
3264
- if (getNodeFromId(node._id) != null) break; // This node is already known.
3265
- node.namel = node.name.toLowerCase();
3266
- if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
3267
- node.meshnamel = meshes[node.meshid]?meshes[node.meshid].name.toLowerCase():'*';
3268
- node.state = 0;
3269
- if (!node.icon) node.icon = 1;
3270
- node.ident = ++nodeShortIdent;
3271
- if (nodes == null) { }
3272
- nodes.push(node);
3273
-
3274
- // Web page update
3275
- mainUpdate(1 | 2 | 4 | 16);
3276
-
3277
- // If we are looking at the device group for this device, update that.
3278
- if ((xxcurrentView == 20) && (currentMesh != null) && (currentMesh._id == node.meshid)) { mainUpdate(4096); }
3279
-
3280
- break;
3281
- }
3282
- case 'removenode': {
3283
- var index = -1;
3284
- for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
3285
- if (index != -1) {
3286
- var node = nodes[index];
3287
- if (currentNode == node) {
3288
- if (xxcurrentView >= 10 && xxcurrentView < 20) { setDialogMode(0); go(1); }
3289
- currentNode = null;
3290
- // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
3291
- }
3292
- nodes.splice(index, 1);
3293
-
3294
- // Web page update
3295
- mainUpdate(4 | 16);
3296
-
3297
- // If we are looking at the device group for this device, update that.
3298
- if ((xxcurrentView == 20) && (currentMesh != null) && (currentMesh._id == node.meshid)) { mainUpdate(4096); }
3299
- }
3300
- break;
3301
- }
3302
- case 'changenode': {
3303
- var index = -1;
3304
- for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
3305
- if (index != -1) {
3306
- var node = nodes[index];
3307
-
3308
- // Change the node
3309
- node.name = message.event.node.name;
3310
- node.rname = message.event.node.rname;
3311
- node.users = message.event.node.users;
3312
- node.host = message.event.node.host;
3313
- node.desc = message.event.node.desc;
3314
- node.ip = message.event.node.ip;
3315
- node.osdesc = message.event.node.osdesc;
3316
- node.publicip = message.event.node.publicip;
3317
- node.iploc = message.event.node.iploc;
3318
- node.wifiloc = message.event.node.wifiloc;
3319
- node.gpsloc = message.event.node.gpsloc;
3320
- node.tags = message.event.node.tags;
3321
- node.ssh = message.event.node.ssh;
3322
- node.rdp = message.event.node.rdp;
3323
- node.userloc = message.event.node.userloc;
3324
- node.rdpport = message.event.node.rdpport;
3325
- node.rfbport = message.event.node.rfbport;
3326
- node.sshport = message.event.node.sshport;
3327
- node.httpport = message.event.node.httpport;
3328
- node.httpsport = message.event.node.httpsport;
3329
- node.consent = message.event.node.consent;
3330
- node.pmt = message.event.node.pmt;
3331
- if (message.event.node.links != null) { node.links = message.event.node.links; } else { delete node.links; }
3332
- if (message.event.node.agent != null) {
3333
- if (node.agent == null) node.agent = {};
3334
- if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; }
3335
- if (message.event.node.agent.id != null) { node.agent.id = message.event.node.agent.id; }
3336
- if (message.event.node.agent.caps != null) { node.agent.caps = message.event.node.agent.caps; }
3337
- if (message.event.node.agent.root != null) { node.agent.root = message.event.node.agent.root; }
3338
- if (message.event.node.agent.core != null) { node.agent.core = message.event.node.agent.core; } else { if (node.agent.core) { delete node.agent.core; } }
3339
- node.agent.tag = message.event.node.agent.tag;
3340
- }
3341
- if (message.event.node.intelamt != null) {
3342
- if (node.intelamt == null) node.intelamt = {};
3343
- if (message.event.node.intelamt.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
3344
- if (message.event.node.intelamt.host != null) { node.intelamt.user = message.event.node.intelamt.host; }
3345
- if (message.event.node.intelamt.user != null) { node.intelamt.user = message.event.node.intelamt.user; } else { delete node.intelamt.user; }
3346
- if (message.event.node.intelamt.tls != null) { node.intelamt.tls = message.event.node.intelamt.tls; }
3347
- if (message.event.node.intelamt.ver != null) { node.intelamt.ver = message.event.node.intelamt.ver; }
3348
- if (message.event.node.intelamt.tag != null) { node.intelamt.tag = message.event.node.intelamt.tag; }
3349
- if (message.event.node.intelamt.uuid != null) { node.intelamt.uuid = message.event.node.intelamt.uuid; }
3350
- if (message.event.node.intelamt.realm != null) { node.intelamt.realm = message.event.node.intelamt.realm; }
3351
- if (message.event.node.intelamt.flags != null) { node.intelamt.flags = message.event.node.intelamt.flags; }
3352
- if (message.event.node.intelamt.warn != null) { node.intelamt.warn = message.event.node.intelamt.warn; } else { delete node.intelamt.warn; }
3353
- }
3354
- if (message.event.node.av != null) { node.av = message.event.node.av; }
3355
- if (message.event.node.wsc != null) { node.wsc = message.event.node.wsc; }
3356
- node.namel = node.name.toLowerCase();
3357
- if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
3358
- if (message.event.node.icon) { node.icon = message.event.node.icon; }
3359
-
3360
- // Check if this device has changed device group
3361
- if (message.event.node.meshid != node.meshid) {
3362
- if ((meshes[message.event.node.meshid] == null) && ((userinfo.links == null) || (userinfo.links[node._id] == null))) {
3363
- // We don't see the new mesh, remove this device
3364
- // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
3365
- if ((currentNode != null) && (currentNode._id == node._id)) {
3366
- if ((xxcurrentView >= 10) && (xxcurrentView < 20) && !IsNodeViewable(currentNode)) { currentNode = null; setDialogMode(0); go(1); }
3367
- }
3368
- var index = -1;
3369
- for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
3370
- nodes.splice(index, 1);
3371
-
3372
- mainUpdate(4 | 16);
3373
- } else {
3374
- // We see the new mesh, move this device
3375
- node.meshid = message.event.node.meshid;
3376
- node.meshnamel = meshes[message.event.node.meshid]?meshes[message.event.node.meshid].name.toLowerCase():'*';
3377
- mainUpdate(1 | 2 | 4);
3378
- }
3379
- }
3380
-
3381
- // Web page update
3382
- updateDeviceViewDevice(node);
3383
- mainUpdate(2 | 8 | 16);
3384
- refreshDevice(node._id);
3385
-
3386
- // If we are looking at the device group for this device, update that.
3387
- if ((xxcurrentView == 20) && (currentMesh != null) && (currentMesh._id == node.meshid)) { mainUpdate(4096); }
3388
-
3389
- if ((currentNode == node) && (xxdialogMode != null) && (xxdialogTag == '@xxmap')) { p10showNodeLocationDialog(); }
3390
- }
3391
- break;
3392
- }
3393
- case 'nodemeshchange': {
3394
- var index = -1;
3395
- for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
3396
- if (index != -1) {
3397
- var node = nodes[index];
3398
- if ((meshes[message.event.newMeshId] == null) && ((userinfo.links == null) || (userinfo.links[node._id] == null))) {
3399
- // We don't see the new mesh, remove this device
3400
-
3401
- // TODO: Correctly disconnect from this node (Desktop/Terminal/Files...)
3402
- if ((currentNode != null) && (currentNode._id == node._id)) {
3403
- if ((xxcurrentView >= 10) && (xxcurrentView < 20) && !IsNodeViewable(currentNode)) { currentNode = null; setDialogMode(0); go(1); }
3404
- }
3405
- nodes.splice(index, 1);
3406
- mainUpdate(4 | 16);
3407
- } else {
3408
- // We see the new mesh, move this device
3409
- node.meshid = message.event.newMeshId;
3410
- node.meshnamel = meshes[message.event.newMeshId]?meshes[message.event.newMeshId].name.toLowerCase():'*';
3411
- mainUpdate(1 | 2 | 4);
3412
- }
3413
- refreshDevice(message.event.nodeid);
3414
- } else {
3415
- // This is a new device, add it.
3416
- var node = message.event.node;
3417
- if (!meshes[node.meshid]) break; // This is a node for a mesh we don't know. Happens when we are site administrator, we get all messages.
3418
- node.namel = node.name.toLowerCase();
3419
- if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
3420
- node.meshnamel = meshes[node.meshid]?meshes[node.meshid].name.toLowerCase():'*';
3421
- node.state = 0;
3422
- if (!node.icon) node.icon = 1;
3423
- node.ident = ++nodeShortIdent;
3424
- if (nodes == null) { }
3425
- nodes.push(node);
3426
-
3427
- // Web page update
3428
- mainUpdate(1 | 2 | 4 | 16);
3429
- }
3430
- break;
3431
- }
3432
- case 'nodeconnect': {
3433
- // Indicated a node has changed connectivity state
3434
- var index = -1;
3435
- for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
3436
- if (index != -1) {
3437
- var node = nodes[index];
3438
-
3439
- // Event the connection change if needed
3440
- var n = getstore('notifications', 0); // Account notification settings
3441
-
3442
- // Per-group notification settings
3443
- if (message.event.meshid && userinfo.links && userinfo.links[message.event.meshid] && userinfo.links[message.event.meshid].notify) {
3444
- n |= userinfo.links[message.event.meshid].notify;
3445
- }
3446
-
3447
- // Per-user notification settings
3448
- if (userinfo.notify != null) {
3449
- if (userinfo.notify[message.event.meshid] != null) { n |= userinfo.notify[message.event.meshid]; }
3450
- if (userinfo.notify[message.event.nodeid] != null) { n |= userinfo.notify[message.event.nodeid]; }
3451
- }
3452
-
3453
- // Show the notification
3454
- if (n & 2) {
3455
- var agentPrivilages = "Agent connected";
3456
- if ((node.agent != null) && (node.agent.root === false)) { "Agent connected with limited privilages"; }
3457
- if (((node.conn & 1) == 0) && ((message.event.conn & 1) != 0)) { addNotification({ text: agentPrivilages, title: node.name, icon: node.icon, nodeid: node._id }); }
3458
- if (((node.conn & 2) == 0) && ((message.event.conn & 2) != 0)) { addNotification({ text: "Intel AMT detected", title: node.name, icon: node.icon, nodeid: node._id }); }
3459
- if (((node.conn & 4) == 0) && ((message.event.conn & 4) != 0)) { addNotification({ text: "Intel AMT CIRA connected", title: node.name, icon: node.icon, nodeid: node._id }); }
3460
- if (((node.conn & 16) == 0) && ((message.event.conn & 16) != 0)) { addNotification({ text: "MQTT connected", title: node.name, icon: node.icon, nodeid: node._id }); }
3461
- }
3462
- if (n & 4) {
3463
- if (((node.conn & 1) != 0) && ((message.event.conn & 1) == 0)) { addNotification({ text: "Agent disconnected", title: node.name, icon: node.icon, nodeid: node._id }); }
3464
- if (((node.conn & 2) != 0) && ((message.event.conn & 2) == 0)) { addNotification({ text: "Intel AMT not detected", title: node.name, icon: node.icon, nodeid: node._id }); }
3465
- if (((node.conn & 4) != 0) && ((message.event.conn & 4) == 0)) { addNotification({ text: "Intel AMT CIRA disconnected", title: node.name, icon: node.icon, nodeid: node._id }); }
3466
- if (((node.conn & 16) != 0) && ((message.event.conn & 16) == 0)) { addNotification({ text: "MQTT disconnected", title: node.name, icon: node.icon, nodeid: node._id }); }
3467
- }
3468
-
3469
- // Change the node connection state
3470
- node.conn = message.event.conn;
3471
- node.pwr = message.event.pwr;
3472
- node.lastconnect = Date.now();
3473
-
3474
- // Clear sesssion and battery information if needed
3475
- if ((node.conn & 1) == 0) { delete node.sessions; }
3476
-
3477
- // Web page update
3478
- var filter = Q('DevFilterSelect').value;
3479
- if ((filter == 1) || (filter == 5)) {
3480
- // We are looking at online or offline devices. This may change that state.
3481
- mainUpdate(1 | 4 | 16);
3482
- } else {
3483
- // We are looking at a different filter, just update that specific device.
3484
- updateDeviceViewDevice(node);
3485
- mainUpdate(1 | 16);
3486
- }
3487
- refreshDevice(node._id);
3488
-
3489
- // If we are looking at the device group for this device, update that.
3490
- if ((xxcurrentView == 20) && (currentMesh != null) && (currentMesh._id == node.meshid)) { mainUpdate(4096); }
3491
- }
3492
- break;
3493
- }
3494
- case 'wssessioncount': {
3495
- // Update the active web socket session count for a user
3496
- if (wssessions != null) {
3497
- if (message.event.count == 0 && wssessions[message.event.userid]) {
3498
- delete wssessions[message.event.userid];
3499
- } else {
3500
- wssessions[message.event.userid] = message.event.count;
3501
- }
3502
- mainUpdate(16384);
3503
- }
3504
- break;
3505
- }
3506
- case 'login': {
3507
- // Update the last login time
3508
- if (users != null && users[message.event.userid]) {
3509
- users[message.event.userid].login = Math.floor(new Date(message.event.time).getTime() / 1000);
3510
- }
3511
- break;
3512
- }
3513
- case 'scanamtdevice': {
3514
- // Populate the Intel AMT scan dialog box with the result of the RMCP scan
3515
- if ((xxdialogMode == null) || (!Q('dp1range')) || (xxdialogTag != ('AMTSCAN:' + message.event.range))) return;
3516
- var x = '';
3517
- if (message.event.results == null) {
3518
- // The scan could not occur because of an error. Likely the user range was invalid.
3519
- x = '<div style=width:100%;text-align:center;margin-top:12px>' + "Unable to scan this address range." + '</div><div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>' + "Sample IP range values" + '<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100</div>';
3520
- } else {
3521
- // Go thru all the results and populate the dialog box
3522
- amtScanResults = message.event.results;
3523
- for (var i in message.event.results) {
3524
- var r = message.event.results[i], shortname = r.hostname;
3525
- if (r.hosttype == 'host') { shortname = capitalizeFirstLetter(shortname.split('.')[0]); }
3526
- if (shortname.length > 20) { shortname = shortname.substring(0, 20) + '...'; }
3527
- var str = '<b title="' + EscapeHtml(r.hostname) + '">' + EscapeHtml(shortname) + '</b> - v' + r.ver;
3528
- if (r.state == 2) { if (r.tls == 1) { str += " with TLS."; } else { str += " without TLS."; } } else { str += ' not activated.'; }
3529
- x += '<div style=width:100%;margin-bottom:2px;background-color:lightgray><div style=padding:4px><div style=display:inline-block;margin-right:5px><input class=DevScanCheckbox name=dp1checkbox tag="' + EscapeHtml(i) + '" type=checkbox onclick=addAmtScanToMeshCheckbox() /></div><div class=j1 style=display:inline-block></div><div style=display:inline-block;margin-left:5px;overflow-x:auto;white-space:nowrap>' + str + '</div></div></div>';
3530
- }
3531
- // If no results where found, display a nice message
3532
- if (x == '') { x = '<div style=width:100%;text-align:center;margin-top:12px>' + "Scan returned no results." + '</div><div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>' + "Sample IP range values" + '<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100</div>'; }
3533
- }
3534
- // Set the html in the dialog box and re-enable the scan button
3535
- QH('dp1results', x);
3536
- QE('dp1range', true);
3537
- QE('dp1rangebutton', true);
3538
- QE('d2scanSelectButton', true);
3539
- break;
3540
- }
3541
- case 'notify': {
3542
- var n = { text: message.event.value, title: message.event.title, icon: message.event.icon, titleid: message.titleid, msgid: message.msgid, args: message.args };
3543
- if (message.id != null) { n.id = message.id; }
3544
- if (message.event.tag != null) { n.tag = message.event.tag; }
3545
- if (typeof message.maxtime == 'number') { n.maxtime = message.maxtime; }
3546
- addNotification(n);
3547
- break;
3548
- }
3549
- case 'traceinfo': {
3550
- if (typeof message.event.traceSources == 'object') {
3551
- if ((message.event.traceSources != null) && (message.event.traceSources.length > 0)) {
3552
- serverTraceSources = message.event.traceSources;
3553
- QH('p41traceStatus', EscapeHtml(message.event.traceSources.join(', ')));
3554
- } else {
3555
- serverTraceSources = [];
3556
- QH('p41traceStatus', "None");
3557
- }
3558
- }
3559
- break;
3560
- }
3561
- case 'sysinfohash': {
3562
- // If the sysinfo document has changed and we are looking at it, request an update.
3563
- if ((currentNode != null) && (message.event.nodeid == powerTimelineReq)) {
3564
- meshserver.send({ action: 'getsysinfo', nodeid: message.event.nodeid });
3565
- }
3566
- break;
3567
- }
3568
- case 'ifchange': {
3569
- // Network interface changed for a device, if we are currently viewing this device, ask for an update.
3570
- if ((currentNode != null) && (currentNode._id == message.event.nodeid)) { meshserver.send({ action: 'getnetworkinfo', nodeid: currentNode._id }); }
3571
- break;
3572
- }
3573
- case 'devicesessions': {
3574
- // List of sessions for a given device
3575
- var node = getNodeFromId(message.event.nodeid);
3576
- if (node == null) break; // Unknown node
3577
- node.sessions = message.event.sessions;
3578
- if (node.sessions != null) {
3579
- for (var i in node.sessions) { if (Object.keys(node.sessions[i]).length == 0) { delete node.sessions[i]; } }
3580
- if (Object.keys(node.sessions).length == 0) { delete node.sessions; }
3581
- }
3582
- updateDeviceViewDevice(node);
3583
- if ((currentNode != null) && (currentNode._id == message.event.nodeid)) { gotoDevice(currentNode._id, xxcurrentView, true); }
3584
-
3585
- // If we are looking at the sessions dialog box for this device now, update it
3586
- if (xxdialogTag == ('SESSIONS-' + message.event.nodeid)) { showDeviceSessions(message.event.nodeid, true); }
3587
- if (xxdialogTag == ('MESSAGES-' + message.event.nodeid)) { showDeviceMessages(message.event.nodeid, true); }
3588
- if (xxdialogTag == ('HELPREQ-' + message.event.nodeid)) { showDeviceHelpRequests(message.event.nodeid, true); }
3589
-
3590
- // If we are filtering on sessions or help, update the visible devices
3591
- if ((Q('DevFilterSelect').value == 2) || (Q('DevFilterSelect').value == 6)) { mainUpdate(1); }
3592
- break;
3593
- }
3594
- case 'loginTokenChanged': { // Login tokens have changed
3595
- if (message.event.userid != userinfo._id) return;
3596
- loginTokens = message.event.loginTokens;
3597
- mainUpdate(65536);
3598
- break;
3599
- }
3600
- case 'loginTokenAdded': { // A login token was added
3601
- if (message.event.userid != userinfo._id) return;
3602
- if (loginTokens == null) { loginTokens = []; }
3603
- loginTokens.push(message.event.newToken);
3604
- mainUpdate(65536);
3605
- break;
3606
- }
3607
- case 'stopped': { // Server is stopping.
3608
- // Disconnect
3609
- //console.log(message.msg);
3610
- break;
3611
- }
3612
- case 'updatePluginList': {
3613
- installedPluginList = message.event.list;
3614
- updatePluginList();
3615
- break;
3616
- }
3617
- case 'pluginStateChange': {
3618
- if (pluginHandler == null) break;
3619
- pluginHandler.refreshPluginHandler();
3620
- break;
3621
- }
3622
- case 'plugin': {
3623
- if (pluginHandler == null) break;
3624
- try { pluginHandler[message.event.plugin][message.event.pluginaction](message); } catch (e) { console.log("PluginHandler could not event message: ", e); }
3625
- break;
3626
- }
3627
- default:
3628
- //console.log('Unknown message.event.action', message.event.action);
3629
- break;
3630
- }
3631
- break;
3632
- }
3633
- case 'createInviteLink': { // Agent installation invitation link
3634
- if (xxdialogTag != message.meshid) break;
3635
- var servername = serverinfo.name;
3636
- if ((servername.indexOf('.') == -1) || ((features & 2) != 0)) { servername = window.location.hostname; } // If the server name is not set or it's in LAN-only mode, use the URL hostname as server name.
3637
- var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
3638
- var url;
3639
- if (serverinfo.https == true) {
3640
- var portStr = (serverinfo.port == 443) ? '' : (':' + serverinfo.port);
3641
- url = 'https://' + servername + portStr + domainUrl + 'agentinvite?c=' + message.cookie + (urlargs.key?('&key=' + urlargs.key):'');
3642
- } else {
3643
- var portStr = (serverinfo.port == 80) ? '' : (':' + serverinfo.port);
3644
- url = 'http://' + servername + portStr + domainUrl + 'agentinvite?c=' + message.cookie + (urlargs.key?('&key=' + urlargs.key):'');
3645
- }
3646
- Q('agentInvitationLink').href = url;
3647
- var t = format((message.expire == 1)?"1 hour":"{0} hours", message.expire);
3648
- if (message.expire == 24) { t = "1 day"; }
3649
- if (message.expire == 168) { t = "1 week"; }
3650
- if (message.expire == 5040) { t = "1 month"; }
3651
- if (message.expire == 0) { t = "Unlimited"; }
3652
- QH('agentInvitationLink', format("Invitation Link ({0})", t));
3653
- QV('agentInvitationLinkDiv', true);
3654
- break;
3655
- }
3656
- case 'createDeviceShareLink': { // Guest sharing link
3657
- if (xxdialogTag) break;
3658
- var node = getNodeFromId(message.nodeid), x = '';
3659
- if (node == null) break;
3660
- x += addHtmlValue("Device", node.name);
3661
- x += addHtmlValue("Guest Name", message.guestname);
3662
- x += addHtmlValue("User Input", message.viewOnly ? "Not allowed, view only" : "Allowed");
3663
- if (message.start && message.expire) {
3664
- if (message.recurring) {
3665
- x += addHtmlValue("Start Time", printDateTime(new Date(message.start)));
3666
- if (message.expire < 2) { x += addHtmlValue("Duration", format("{0} minute", message.expire) ); }
3667
- else { x += addHtmlValue("Duration", format("{0} minutes", message.expire) ); }
3668
- } else {
3669
- x += addHtmlValue("Start Time", printDateTime(new Date(message.start)));
3670
- x += addHtmlValue("Expire Time", printDateTime(new Date(message.expire)));
3671
- }
3672
- }
3673
- if (message.recurring == 1) { x += addHtmlValue("Recurring", "Daily"); }
3674
- if (message.recurring == 2) { x += addHtmlValue("Recurring", "Weekly"); }
3675
- var y = [];
3676
- if (message.consent & 0x0007) { y.push("Notify"); }
3677
- if (message.consent & 0x0038) { y.push("Prompt"); }
3678
- if (message.consent & 0x0040) { y.push("Privacy bar"); }
3679
- if (y.length == 0) { y.push("None"); }
3680
- x += addHtmlValue("User Consent", y.join(', '));
3681
- var type = ''; if (message.p <= 7) { type = ['', "Remote Terminal Link", "Remote Desktop Link", "Remote Desktop + Terminal Link", "Remote Files Link", "Remote Terminal + Files Link", "Remote Desktop + Files Link", "Remote Desktop + Terminal + Files Link"][message.p]; } else if (message.p == 8) { type = format("HTTP/{0} link", message.port); } else if (message.p == 16) { type = format("HTTPS/{0}", message.port); }
3682
- x += '<div id=agentInvitationLinkDiv style="text-align:center;font-size:large;margin:16px"><a href="' + message.url + '" id=agentInvitationLink rel="noreferrer noopener" target="_blank" style=cursor:pointer>' + type + '</a> <img src=images/link4.png height=10 width=10 title="' + "Copy link to clipboard" + '" style=cursor:pointer onclick=d2CopyInviteToClip()></div></div>';
3683
- setDialogMode(2, "Share Device", 1, null, x);
3684
- break;
3685
- }
3686
- case 'getmqttlogin': {
3687
- if ((currentNode == null) || (currentNode._id != message.nodeid) || (xxdialogMode != null)) return;
3688
- var x = "These settings can be used to connect MQTT for this device." + '<br /><br />';
3689
- delete message.action;
3690
- delete message.nodeid;
3691
- x += '<textarea readonly=readonly style=width:100%;resize:none;height:100px;overflow:auto;font-size:12px readonly>' + JSON.stringify(message) + '</textarea>';
3692
- /*
3693
- x += addHtmlValue('Username', '<input style=width:230px readonly value="' + message.user + '" />');
3694
- x += addHtmlValue('Password', '<input style=width:230px readonly value="' + message.pass + '" />');
3695
- x += addHtmlValue('WS URL', '<input style=width:230px readonly value="' + message.wsUrl + '" />');
3696
- if (message.mpsUrl && message.mpsCertHash) {
3697
- x += addHtmlValue('MPS URL', '<input style=width:230px readonly value="' + message.mpsUrl + '" />');
3698
- x += addHtmlValue('MPS Cert Hash', '<input style=width:230px readonly value="' + message.mpsCertHash + '" />');
3699
- }
3700
- */
3701
- setDialogMode(2, "MQTT Credentials", 1, null, x);
3702
- break;
3703
- }
3704
- case 'stopped': { // Server is stopping.
3705
- // Disconnect
3706
- autoReconnect = false;
3707
- QH('p0span', message.msg);
3708
- break;
3709
- }
3710
- case 'updatePluginList': {
3711
- installedPluginList = message.list;
3712
- updatePluginList();
3713
- break;
3714
- }
3715
- case 'pluginVersionsAvailable': {
3716
- if (pluginHandler == null) break;
3717
- updatePluginList(message.list);
3718
- break;
3719
- }
3720
- case 'downgradePluginVersions': {
3721
- var vSelect = '<select id="lastPluginVersion">';
3722
- message.info.versionList.forEach(function(v) { vSelect += '<option value="' + v.zipball_url + '">' + v.name + '</option>'; });
3723
- vSelect += '</select>';
3724
- setDialogMode(2, "Plugin Action", 3, pluginActionEx, format('Select the version to downgrade the plugin: {0}', message.info.name) + '<hr />' + vSelect + '<hr />' + "Please be aware that downgrading is not recommended. Please only do so in the event that a recent upgrade has broken something." + + '<input id="lastPluginAct" type="hidden" value="downgrade" /><input id="lastPluginId" type="hidden" value="' + message.info.id + '" />');
3725
- break;
3726
- }
3727
- case 'serverBackup': {
3728
- if (message.service == 'googleDrive') {
3729
- QV('p2ServerActionsGoogleBackup', message.state > 0);
3730
- QV('p2ServerActionsGoogleBackupCheck', message.state > 2);
3731
- miscState['googleDrive'] = { state: message.state }
3732
- if (message.state == 2) {
3733
- var x = '<img style=float:right src="images/googledrive-48.png" /><div>' + "Nagivate to the URL below, grant access and copy the token code back." + '</div><br />';
3734
- x += addHtmlValue("Activation", '<a href=\"' + message.url + '\" rel="noreferrer noopener" target="_blank">Browse to this URL</a>');
3735
- x += addHtmlValue("Code", '<input id=gdcode onkeyup=server_setupGoogleDriveBackupCheck3() style=width:240px></input>');
3736
- setDialogMode(2, "Google Drive Backup", 3, server_setupGoogleDriveBackupEx, x, 'gd2');
3737
- Q('gdcode').focus();
3738
- QE('idx_dlgOkButton', false);
3739
- }
3740
- }
3741
- break;
3742
- }
3743
- case 'pluginError': {
3744
- setDialogMode(2, "Plugin Error", 1, null, message.msg);
3745
- break;
3746
- }
3747
- case 'plugin': {
3748
- if ((pluginHandler == null) || (typeof message.plugin != 'string')) break;
3749
- try { pluginHandler[message.plugin][message.method](server, message); } catch (e) { console.log('Error loading plugin handler ('+ e + ')'); }
3750
- break;
3751
- }
3752
- case 'amtsetupbin': {
3753
- saveAs(new Blob([ Uint8Array.from(atob(message.file), function (c) { return c.charCodeAt(0) }) ], { type: 'application/octet-stream' }), 'setup.bin');
3754
- break;
3755
- }
3756
- case 'previousLogins':{
3757
- var tag = 'previousLogins';
3758
- if (message.userid != null) { tag += ':' + message.userid; }
3759
- if ((xxdialogMode == 2) && (xxdialogTag == tag)) {
3760
- var x = '', c = 'BBB', xx = '';
3761
- if (message.events.length == 0) {
3762
- x += 'No previous login.';
3763
- } else {
3764
- x += '<div style=max-height:260px;overflow-y:scroll;overflow-x:hidden><table>';
3765
- for (var i in message.events) {
3766
- var m = message.events[i].m;
3767
- if (m == 107) { m = "Valid login"; c = 'BBD1BB'; xx = ''; if (message.events[i].tn != null) { m = format("Token: {0}", message.events[i].tn); c = '88D188' } }
3768
- else if (m == 108) { m = "Invalid 2FA"; c ='DD9DC3'; xx = 'x'; }
3769
- else if (m == 109) { m = "Locked account"; c ='E1BBBB'; xx = 'x'; }
3770
- else if (m == 110) { m = "Invalid password"; c = 'E1BBBB'; xx = 'x'; }
3771
- x += '<tr><td><img src=images/user-32' + xx + '.png height=32 width=32 style=float:left srcset="images/user-64' + xx + '.png 2x"><td><div style=width:300px;background-color:#' + c + ';border-radius:6px;margin-bottom:4px;padding:4px><div>' + printDateTime(new Date(message.events[i].t)) + ', <b>' + EscapeHtml(m) + '</b></div><div style=font-size:x-small>' + EscapeHtml(message.events[i].a.join(', ')) + '</div></div></tr>';
3772
- }
3773
- x += '</table></div>';
3774
- }
3775
- setDialogMode(2, "Previous Logins", 1, null, x);
3776
- }
3777
- break;
3778
- }
3779
- case 'getDeviceDetails': {
3780
- saveAs(new Blob([message.data], { type: 'application/octet-stream' }), "devicelist" + '.' + message.type);
3781
- break;
3782
- }
3783
- case 'createLoginToken': { // A new login token was created
3784
- if (xxdialogMode) return;
3785
- var x = "Take note of this username and password, the password cannot be shown again." + '<br /><br />';
3786
- x += addHtmlValue("Name", EscapeHtml(message.name))
3787
- if (message.expire != 0) { x += addHtmlValue("Expire", EscapeHtml(printDateTime(new Date(message.expire)))); }
3788
- x += addHtmlValue("Username", '<img src="images/link4.png" title="' + "Copy link to clipboard" + '" style="margin:9px;cursor:pointer;float:right" onclick=copyTextToClip2("' + encodeURIComponentEx(message.tokenUser) + '") width=10 height=10><div class=selecttext style=width:230px;padding:5px;background-color:orange;border-radius:5px;font-size:15px>' + EscapeHtml(message.tokenUser) + '</div>');
3789
- x += addHtmlValue("Password", '<img src="images/link4.png" title="' + "Copy link to clipboard" + '" style="margin:9px;cursor:pointer;float:right" onclick=copyTextToClip2("' + encodeURIComponentEx(message.tokenPass) + '") width=10 height=10><div class=selecttext style=width:230px;padding:5px;background-color:orange;border-radius:5px;font-size:15px>' + EscapeHtml(message.tokenPass) + '</div>');
3790
- setDialogMode(2, "Create Login Token", 1, null, x);
3791
- break;
3792
- }
3793
- case 'loginTokens': { // Reveiced the list of login tokens
3794
- loginTokens = message.loginTokens;
3795
- mainUpdate(65536);
3796
- break;
3797
- }
3798
- case 'report': {
3799
- renderReport(message.data);
3800
- break;
3801
- }
3802
- default:
3803
- //console.log('Unknown message.action', message.action);
3804
- break;
3805
- }
3806
- }
3807
-
3808
- // Go to the correct starting view page
3809
- function gotoStartViewPage() {
3810
- var xviewmode = parseInt('{{viewmode}}');
3811
- if (xxcurrentView != -1) return;
3812
- if ('{{currentNode}}'.toLowerCase() != '') { // The .toLowerCase here is the minifier will not optimize this out.
3813
- if (getNodeFromId('{{currentNode}}') == null) return; // This node is not loaded yet
3814
- gotoDevice('{{currentNode}}', xviewmode);
3815
- } else if (args.gotonode != null) {
3816
- if (args.gotonode.length == 96) { args.gotonode = btoa(hex2rstr(args.gotonode)).split('+').join('@').split('/').join('$'); } // This is a HEX encoded NodeID, convert it to Base64
3817
- if (getNodeFromId('node/' + domain + '/' + args.gotonode) == null) return; // This node is not loaded yet
3818
- gotoDevice('node/' + domain + '/' + args.gotonode, xviewmode);
3819
- goBackStack.push(1);
3820
- } else if (args.gotodevicename != null) {
3821
- var foundNode = null;
3822
- if (nodes != null) { for (var i in nodes) { if (nodes[i].name == args.gotodevicename) { foundNode = nodes[i]._id; } } }
3823
- if (foundNode) { gotoDevice(foundNode, xviewmode); goBackStack.push(1); }
3824
- } else if (args.gotomesh != null) {
3825
- if (meshes['mesh/' + domain + '/' + args.gotomesh] == null) return; // This device group is not loaded yet
3826
- gotoMesh('mesh/' + domain + '/' + args.gotomesh);
3827
- go(xviewmode);
3828
- goBackStack.push(2);
3829
- } else if (args.gotouser != null) {
3830
- var xuserid = args.gotouser;
3831
- if (args.gotouser.indexOf('/') < 0) { xuserid = 'user/' + domain + '/' + args.gotouser; }
3832
- if ((users == null) || (users[xuserid] == null)) return; // This user is not loaded yet
3833
- gotoUser(encodeURIComponentEx(xuserid));
3834
- go(xviewmode);
3835
- goBackStack.push(4);
3836
- } else if (args.gotougrp != null) {
3837
- var xusergrpid = args.gotougrp;
3838
- if (args.gotougrp.indexOf('/') < 0) { xusergrpid = 'ugrp/' + domain + '/' + args.gotougrp; }
3839
- if ((usergroups == null) || usergroups[xusergrpid] == null) return; // This user group is not loaded yet
3840
- gotoUserGroup(xusergrpid);
3841
- go(xviewmode);
3842
- goBackStack.push(50);
3843
- } else if (!isNaN(xviewmode)) {
3844
- go(xviewmode);
3845
- } else {
3846
- setDialogMode(0);
3847
- go(1);
3848
- }
3849
- delete args.gotonode;
3850
- delete args.gotomesh;
3851
- delete args.gotouser;
3852
- delete args.gotougrp;
3853
- }
3854
-
3855
- //
3856
- // MY DEVICES
3857
- //
3858
-
3859
- function onRealNameCheckBox() {
3860
- showRealNames = Q('RealNameCheckBox').checked;
3861
- putstore('showRealNames', showRealNames ? 1 : 0);
3862
- mainUpdate(7);
3863
- }
3864
-
3865
- function onOnlineCheckBox(e) {
3866
- putstore('devFilterSelect', Q('DevFilterSelect').value);
3867
- onDeviceSearchChanged(e);
3868
- }
3869
-
3870
- function updateDevicePageState() {
3871
- if ((devicePagingState == null) || (devicePagingState.total <= devicePagingState.limit)) {
3872
- QV('devViewPageState', false);
3873
- QV('devViewPageButton1', false);
3874
- QV('devViewPageButton2', false);
3875
- QV('devViewPageButton3', false);
3876
- QV('devViewPageButton4', false);
3877
- } else {
3878
- var currentPage = Math.floor((devicePagingState.skip + devicePagingState.limit) / devicePagingState.limit);
3879
- var maxPage = Math.ceil(devicePagingState.total / devicePagingState.limit);
3880
- QV('devViewPageState', true);
3881
- QV('devViewPageButton1', true);
3882
- QV('devViewPageButton2', true);
3883
- QV('devViewPageButton3', true);
3884
- QV('devViewPageButton4', true);
3885
- QH('devViewPageState', currentPage + '/' + maxPage);
3886
- }
3887
- }
3888
-
3889
- function onDeviceViewPageChange(i) {
3890
- if (devicePagingState == null) return;
3891
- var currentPage = (Math.floor((devicePagingState.skip + devicePagingState.limit) / devicePagingState.limit));
3892
- var maxPage = Math.ceil(devicePagingState.total / devicePagingState.limit);
3893
- switch (i) {
3894
- case 1: { if (currentPage > 1) meshserver.send({ action: 'nodes', skip: 0 }); break; } // Goto first page
3895
- case 2: { if (currentPage > 1) meshserver.send({ action: 'nodes', skip: (currentPage - 2) * devicePagingState.limit }); break; } // Goto previous page
3896
- case 3: { if (currentPage < maxPage) meshserver.send({ action: 'nodes', skip: currentPage * devicePagingState.limit }); break; } // Goto next page
3897
- case 4: { if (currentPage < maxPage) meshserver.send({ action: 'nodes', skip: (maxPage - 1) * devicePagingState.limit }); break; } // Goto last page
3898
- }
3899
- }
3900
-
3901
- function onDeviceViewChange(i) {
3902
- if (i != null) { Q('viewselect').value = i; }
3903
- for (var j = 1; j < 6; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
3904
- Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
3905
- putstore('deviceView', Q('viewselect').value);
3906
- putstore('viewsize', Q('sizeselect').value);
3907
- mainUpdate(4);
3908
- setTimeout(function () { mainUpdate(512); }, 200);
3909
- }
3910
-
3911
- function onDeviceViewSettings() {
3912
- if (xxdialogMode) return;
3913
-
3914
- // Use defaults if needed
3915
- if (deviceViewSettings == null) { deviceViewSettings = {}; }
3916
- if (!Array.isArray(deviceViewSettings.devsCols)) { deviceViewSettings.devsCols = ['user','ip','conn']; }
3917
-
3918
- // Display the dialog box
3919
- var x = '';
3920
- x += '<label><input id=d2c8 type=checkbox' + ((deviceViewSettings.devsCols.indexOf('agtype') >= 0)?' checked':'') + '>' + "Agent Type" + '</label><br />';
3921
- x += '<label><input id=d2c9 type=checkbox' + ((deviceViewSettings.devsCols.indexOf('agver') >= 0)?' checked':'') + '>' + "Agent Version" + '</label><br />';
3922
- x += '<label><input id=d2c6 type=checkbox' + ((deviceViewSettings.devsCols.indexOf('desc') >= 0)?' checked':'') + '>' + "Device Description" + '</label><br />';
3923
- x += '<label><input id=d2c5 type=checkbox' + ((deviceViewSettings.devsCols.indexOf('os') >= 0)?' checked':'') + '>' + "Operating System" + '</label><br />';
3924
- x += '<label><input id=d2c1 type=checkbox' + ((deviceViewSettings.devsCols.indexOf('links') >= 0)?' checked':'') + '>' + "MeshCentral Router Links" + '</label><br />';
3925
- x += '<label><input id=d2c2 type=checkbox' + ((deviceViewSettings.devsCols.indexOf('user') >= 0)?' checked':'') + '>' + "Logged in users" + '</label><br />';
3926
- x += '<label><input id=d2c3 type=checkbox' + ((deviceViewSettings.devsCols.indexOf('ip') >= 0)?' checked':'') + '>' + "Agent IP address" + '</label><br />';
3927
- x += '<label><input id=d2c4 type=checkbox' + ((deviceViewSettings.devsCols.indexOf('conn') >= 0)?' checked':'') + '>' + "Server Connectivity" + '</label><br />';
3928
- x += '<label><input id=d2c7 type=checkbox' + ((deviceViewSettings.devsCols.indexOf('lastseen') >= 0)?' checked':'') + '>' + "Last Seen" + '</label><br />';
3929
- setDialogMode(2, "Device View Columns", 3, onDeviceViewSettingsEx, x);
3930
- }
3931
-
3932
- function onDeviceViewSettingsEx() {
3933
- var cols = [];
3934
- if (Q('d2c1').checked) { cols.push('links'); }
3935
- if (Q('d2c2').checked) { cols.push('user'); }
3936
- if (Q('d2c3').checked) { cols.push('ip'); }
3937
- if (Q('d2c4').checked) { cols.push('conn'); }
3938
- if (Q('d2c5').checked) { cols.push('os'); }
3939
- if (Q('d2c6').checked) { cols.push('desc'); }
3940
- if (Q('d2c7').checked) { cols.push('lastseen'); }
3941
- if (Q('d2c8').checked) { cols.push('agtype'); }
3942
- if (Q('d2c9').checked) { cols.push('agver'); }
3943
- deviceViewSettings.devsCols = cols;
3944
- putstore('_deviceViewSettings', JSON.stringify(deviceViewSettings));
3945
- mainUpdate(4);
3946
- }
3947
-
3948
- function ondockeypress(e) {
3949
- setSessionActivity();
3950
- if (!xxdialogMode && (xxcurrentView == 11) && desktop && Q('DeskControl').checked) {
3951
- // Check what keys we are allows to send
3952
- if (currentNode != null) {
3953
- var meshrights = GetNodeRights(currentNode);
3954
- var inputAllowed = ((features2 & 0x2000) == 0) && ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
3955
- if (inputAllowed == false) return false;
3956
- var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
3957
- if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
3958
- }
3959
- return desktop.m.handleKeys(e);
3960
- }
3961
- if (!xxdialogMode && (xxcurrentView == 12) && terminal && (terminal.State == 3) && (xterm == null)) { return terminal.m.TermHandleKeys(e); }
3962
- if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) return agentConsoleHandleKeys(e);
3963
- if (!xxdialogMode && xxcurrentView == 4) {
3964
- if ((e.ctrlKey == true) || (e.altKey == true) || (e.metaKey == true)) return;
3965
- var processed = 0;
3966
- if (e.key) {
3967
- if ((e.key.length === 1) && (userSearchFocus == 0)) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + e.key)); processed = 1; }
3968
- if ((e.keyCode == 8) && (userSearchFocus == 0)) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = x.substring(0, x.length - 1); processed = 1; }
3969
- if (e.keyCode == 27) { Q('UserSearchInput').value = ''; processed = 1; }
3970
- } else {
3971
- if (e.charCode != 0 && userSearchFocus == 0) { Q('UserSearchInput').value = ((Q('UserSearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
3972
- }
3973
- if (processed > 0) { if (processed == 1) { onUserSearchInputChanged(); } return haltEvent(e); }
3974
- }
3975
- if (xxdialogMode || xxcurrentView != 1) return;
3976
- if (e.ctrlKey == true && e.charCode == 96) {
3977
- showRealNames = !showRealNames;
3978
- Q('RealNameCheckBox').value = showRealNames;
3979
- putstore('showRealNames', showRealNames ? 1 : 0);
3980
- mainUpdate(6)
3981
- return;
3982
- }
3983
- if (e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
3984
- if (Q('viewselect').value < 4) {
3985
- var processed = 0;
3986
- if (e.key) {
3987
- if ((e.key.length === 1) && (searchFocus == 0)) { Q('KvmSearchInput').value = Q('SearchInput').value = ((Q('SearchInput').value + e.key)); processed = 1; }
3988
- if ((e.keyCode == 8) && (searchFocus == 0)) { var x = Q('SearchInput').value; Q('KvmSearchInput').value = Q('SearchInput').value = x.substring(0, x.length - 1); processed = 1; }
3989
- if (e.keyCode == 27) { Q('KvmSearchInput').value = Q('SearchInput').value = ''; processed = 1; }
3990
- } else {
3991
- if (e.charCode != 0 && searchFocus == 0) { Q('KvmSearchInput').value = Q('SearchInput').value = ((Q('SearchInput').value + String.fromCharCode(e.charCode))); processed = 1; }
3992
- }
3993
- if (processed > 0) { if (processed == 1) { mainUpdate(5); } return haltEvent(e); }
3994
- }
3995
- if (Q('viewselect').value == 4) {
3996
- if (e.key) {
3997
- if ((e.key.length === 1) && (mapSearchFocus == 0)) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + e.key)); processed = 1; }
3998
- //if (e.keyCode == 8 && mapSearchFocus == 0) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = x.substring(0, x.length - 1); processed = 1; }
3999
- if (e.keyCode == 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
4000
- if (e.keyCode == 13) { getSearchLocation(); }
4001
- } else {
4002
- if (e.charCode != 0 && mapSearchFocus == 0) { Q('mapSearchLocation').value = ((Q('mapSearchLocation').value + String.fromCharCode(e.charCode))); processed = 1; }
4003
- }
4004
- }
4005
- }
4006
-
4007
- function ondockeydown(e) {
4008
- setSessionActivity();
4009
- if (!xxdialogMode && (xxcurrentView == 11) && desktop && Q('DeskControl').checked) {
4010
- // Check what keys we are allows to send
4011
- if (currentNode != null) {
4012
- var meshrights = GetNodeRights(currentNode);
4013
- var inputAllowed = ((features2 & 0x2000) == 0) && ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
4014
- if (inputAllowed == false) return false;
4015
- var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
4016
- if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
4017
- }
4018
- return desktop.m.handleKeyDown(e);
4019
- }
4020
- if (!xxdialogMode && (xxcurrentView == 12) && terminal && (terminal.State == 3) && xterm == null) { terminal.m.TermHandleKeyDown(e); if ((e.keyCode >= 37) && (e.keyCode <= 40)) { haltEvent(e); } }
4021
- if (!xxdialogMode && (xxcurrentView == 13) && (e.keyCode == 116) && (p13filetree != null)) { haltEvent(e); return false; } // F5 Refresh on files
4022
- if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) { return agentConsoleHandleKeys(e); }
4023
- if (!xxdialogMode && (xxcurrentView == 4)) {
4024
- if ((e.keyCode === 8) && (userSearchFocus == 0)) { var x = Q('UserSearchInput').value; Q('UserSearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
4025
- if (e.keyCode === 27) { Q('UserSearchInput').value = ''; processed = 1; }
4026
- if (processed > 0) { if (processed == 1) { mainUpdate(5); } return haltEvent(e); }
4027
- }
4028
- if (xxdialogMode || (xxcurrentView != 1) || (e.ctrlKey == true) || (e.altKey == true) || (e.metaKey == true)) return;
4029
- var processed = 0;
4030
- if (Q('viewselect').value < 4) {
4031
- if ((e.keyCode === 8) && (searchFocus == 0)) { var x = Q('SearchInput').value; Q('KvmSearchInput').value = Q('SearchInput').value = (x.substring(0, x.length - 1)); processed = 1; }
4032
- if (e.keyCode === 27) { Q('KvmSearchInput').value = Q('SearchInput').value = ''; processed = 1; }
4033
- if (processed > 0) { if (processed == 1) { mainUpdate(5); } return haltEvent(e); }
4034
- }
4035
- if (Q('viewselect').value == 4) {
4036
- if ((e.keyCode === 8) && (mapSearchFocus == 0)) { var x = Q('mapSearchLocation').value; Q('mapSearchLocation').value = (x.substring(0, x.length - 1)); processed = 1; }
4037
- if (e.keyCode === 27) { Q('mapSearchLocation').value = ''; mapCloseSearchWindow(); processed = 1; }
4038
- }
4039
- }
4040
-
4041
- function ondockeyup(e) {
4042
- setSessionActivity();
4043
- if (!xxdialogMode && (xxcurrentView == 11) && desktop && Q('DeskControl').checked) {
4044
- // Check what keys we are allows to send
4045
- if (currentNode != null) {
4046
- var meshrights = GetNodeRights(currentNode);
4047
- var inputAllowed = ((features2 & 0x2000) == 0) && ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
4048
- if (inputAllowed == false) return false;
4049
- var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
4050
- if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || ((e.keyCode < 32) && (e.keyCode != 8) && (e.keyCode != 13)) || (e.keyCode > 90)) return false; }
4051
- }
4052
- return desktop.m.handleKeyUp(e);
4053
- }
4054
- if (!xxdialogMode && (xxcurrentView == 12) && terminal && (terminal.State == 3) && xterm == null) { return terminal.m.TermHandleKeyUp(e); }
4055
- if (!xxdialogMode && (xxcurrentView == 13) && (e.keyCode == 116) && (p13filetree != null)) { p13folderup(9999); haltEvent(e); return false; } // F5 Refresh on files
4056
- if (!xxdialogMode && (xxcurrentView == 4)) { if (((e.keyCode === 8) && (searchFocus == 0)) || e.keyCode === 27) { return haltEvent(e); } }
4057
- if (xxdialogMode && (e.keyCode == 27)) { dialogclose(0); }
4058
- if ((e.shiftKey == true) && (e.keyCode == 27)) { dialogclose(0); Q('KvmSearchInput').value = Q('SearchInput').value = ''; mainUpdate(5); if (desktop != null) { connectDesktop(); } if (terminal != null) { connectTerminal(); } if (files != null) { connectFiles(); } go(1); return; } // Shift-ESC: Reset the web page
4059
- if (xxdialogMode || xxcurrentView != 0 || e.ctrlKey == true || (e.altKey == true) || (e.metaKey == true)) return;
4060
- if (Q('viewselect').value < 4) { if (((e.keyCode === 8) && (searchFocus == 0)) || (e.keyCode === 27)) { return haltEvent(e); } }
4061
- if (Q('viewselect').value == 4) { if (((e.keyCode === 8) && (mapSearchFocus == 0)) || (e.keyCode === 27)) { return haltEvent(e); } }
4062
- }
4063
-
4064
- //function ondocfocus() { }
4065
- // TODO: Add handleReleaseKeys() for Intel AMT.
4066
- function ondocblur() { if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked && desktop.m.handleReleaseKeys) { return desktop.m.handleReleaseKeys(); } }
4067
-
4068
- // Highlights the device group hovered
4069
- function devGrpMouseHover(element, over) {
4070
- setSessionActivity();
4071
- var view = Q('viewselect').value;
4072
- var e = element.children[1].children[1];
4073
- e.children[0].classList.remove('g1s');
4074
- e.children[1].classList.remove('e2s');
4075
- e.children[2].classList.remove('g2s');
4076
- if (over == 1) {
4077
- e.children[0].classList.add('g1s');
4078
- e.children[1].classList.add('e2s');
4079
- e.children[2].classList.add('g2s');
4080
- }
4081
- }
4082
-
4083
- // Highlights the device being hovered
4084
- function devMouseHover(element, over) {
4085
- setSessionActivity();
4086
- var view = Q('viewselect').value;
4087
- if (view == 1) {
4088
- var e = element.children[0].children[0].children[1].children[0].children[0].children[0];
4089
- e.children[1].classList.remove('g1s');
4090
- e.children[2].classList.remove('e2s');
4091
- e.children[3].classList.remove('g2s');
4092
- if (over == 1) {
4093
- e.children[1].classList.add('g1s');
4094
- e.children[2].classList.add('e2s');
4095
- e.children[3].classList.add('g2s');
4096
- }
4097
- } else if (view == 2) {
4098
- var e = element;
4099
- e.children[2].classList.remove('g1s');
4100
- e.children[4].classList.remove('e2s');
4101
- e.children[3].classList.remove('g2s');
4102
- if (over == 1) {
4103
- e.children[2].classList.add('g1s');
4104
- e.children[4].classList.add('e2s');
4105
- e.children[3].classList.add('g2s');
4106
- }
4107
- }
4108
- }
4109
-
4110
- var deviceHeaderId = 0;
4111
- var deviceHeaderTotal = 0;
4112
- var deviceHeadersTitles = {};
4113
- var deviceHeaderCount;
4114
- var deviceHeaders = {};
4115
- var oldviewmode = 0;
4116
- function updateDevices() {
4117
- if ((nodes == null) || (xxcurrentView != 1)) { return; }
4118
- var r = '', c = 0, current = null, count = 0, scount = 0, displayedMeshes = {}, view = Q('viewselect').value, groups = {}, groupCount = {};
4119
- QV('xdevices', view != 4);
4120
- QV('xdevicesmap', view == 4);
4121
- QV('devListToolbar', view < 3);
4122
- QV('kvmListToolbar', (view == 3) || (view == 5));
4123
- QV('devMapToolbar', view == 4);
4124
- QV('devListToolbarSize', (view == 3) || (view == 5));
4125
- QV('devListToolbarSettings', view == 2);
4126
- QV('NoMeshesPanel', (nodes.length == 0) && (meshcount == 0));
4127
- //QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
4128
- QV('devListToolbarViewIcons', nodes.length > 0);
4129
- QV('devListToolbarSort', (nodes.length > 0) && (view != 4));
4130
- if (nodes.length == 0) { view = 1; sort = 0; }
4131
- if (view == 4) {
4132
- setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200);
4133
- // TODO
4134
- } else {
4135
- // 3 wide, list view or desktop view
4136
- deviceHeaderId = 0;
4137
- deviceHeaderCount = {};
4138
- deviceHeaderTotal = 0;
4139
- deviceHeaders = {};
4140
- deviceHeadersTitles = {};
4141
- var kvmDivs = [];
4142
-
4143
- // Perform node sort
4144
- if (sort == 0) { nodes.sort(meshSort); }
4145
- else if (sort == 1) { nodes.sort(powerSort); }
4146
- else if (sort == 2) { if (showRealNames == true) { nodes.sort(deviceHostSort); } else { nodes.sort(deviceSort); } }
4147
- else if (sort == 5) {
4148
- // If the last seen column is not turned on, turn it on first (we require this to sort the data)
4149
- if (!(deviceViewSettings && deviceViewSettings.devsCols && deviceViewSettings.devsCols.indexOf('lastseen') >= 0)) {
4150
- // Request last connection data if not requested yet
4151
- if (requestedLastConnects == false) { requestedLastConnects = true; meshserver.send({ action: 'lastconnects' }); }
4152
- // Force initialize the view settings
4153
- if (deviceViewSettings == null) { deviceViewSettings = {}; }
4154
- if (!Array.isArray(deviceViewSettings.devsCols)) { deviceViewSettings.devsCols = ['user','ip','conn', 'lastseen']; }
4155
- else { deviceViewSettings.devsCols.push('lastseen'); }
4156
- }
4157
- nodes.sort(lastConnectSort);
4158
- }
4159
-
4160
- // Compute the width of the device view.
4161
- var totalDeviceViewWidth = Q('column_l').clientWidth - 60;
4162
- var deviceBoxWidth = Math.floor(totalDeviceViewWidth / 301);
4163
- deviceBoxWidth = 301 + Math.floor((totalDeviceViewWidth - (deviceBoxWidth * 301)) / deviceBoxWidth);
4164
-
4165
- // Compute number of colums
4166
- var colcount = 4;
4167
- if (deviceViewSettings && deviceViewSettings.devsCols) {
4168
- colcount = deviceViewSettings.devsCols.length + 1;
4169
- if (deviceViewSettings.devsCols.indexOf('desc') >= 0) { colcount--; } // Description is not an extra column.
4170
- }
4171
-
4172
- // Go thru the list of nodes and display them
4173
- for (var i in nodes) {
4174
- var node = nodes[i];
4175
- if (node.v == false) continue;
4176
- var mesh2 = meshes[node.meshid];
4177
- //if ((view == 3) && (mesh2.mtype == 1)) continue;
4178
- var meshrights = GetNodeRights(node);
4179
- if (sort == 0) {
4180
- // Mesh header
4181
- if (((meshes[node.meshid]?node.meshid:'*') != current)) {
4182
- if (((view == 1) || (view == 3) || (view == 5)) && (current != null)) { r += '</div>'; } // Close collapse div
4183
- deviceHeaderSet();
4184
- var extra = '';
4185
- if (view == 2) { r += '<tr><td colspan=' + colcount + '>'; }
4186
- if (meshes[node.meshid] && (meshes[node.meshid].mtype == 1)) { extra = '<span class=devHeaderx>' + ", Intel® AMT only" + '</span>'; }
4187
- if (meshes[node.meshid] && (meshes[node.meshid].mtype == 3)) { if (meshes[node.meshid].relayid) { extra = '<span class=devHeaderx>' + ", Relayed Devices" + '</span>'; } else { extra = '<span class=devHeaderx>' + ", Local Devices" + '</span>'; } }
4188
- if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
4189
- if (view == 2) { r += '<div>'; }
4190
- r += '<div class=DevSt style=width:100%;padding-top:4px><span style=float:right>';
4191
- r += '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span>' + extra;
4192
- r += '</span>';
4193
- if ((view == 1) || (view == 2) || (view == 3) || (view == 5)) {
4194
- var collapsed = CollapsedGroups[node.meshid];
4195
- r += '<img class=collapseImage cmenu=expandAllContextMenu id="DevxColImg' + deviceHeaderId + '" src=images/c' + ((collapsed === true)?'1':'2') + '.png height=8 width=8 style=margin-left:2px;margin-right:2px;cursor:pointer onclick=toggleCollapseGroup("' + deviceHeaderId + '","' + node.meshid + '",' + view + ')></img>'; // Collapse action
4196
- }
4197
- if (meshes[node.meshid]) {
4198
- r += '<span id=MxMESH cmenu=meshContextMenu tabindex=0 style=cursor:pointer onclick=gotoMesh("' + node.meshid + '") onkeypress="if (event.key==\'Enter\') gotoMesh(\'' + node.meshid + '\')">' + EscapeHtml(meshes[node.meshid].name) + '</span>' + getMeshActions(mesh2, meshrights) + '</div>';
4199
- current = node.meshid;
4200
- } else {
4201
- r += '<span id=MxMESH><i>' + "Individual Devices" + '</i></span></div>';
4202
- current = '*';
4203
- }
4204
- if (view == 2) { r += '</div>'; }
4205
- displayedMeshes[current] = 1;
4206
- c = 0;
4207
- if ((view == 1) || (view == 3) || (view == 5)) { r += '<div id=DevxCol' + deviceHeaderId + ((collapsed === true)?' style=display:none':'') + '>'; } // Open collapse div
4208
- }
4209
- } else if (sort == 1) {
4210
- // Power header
4211
- var pwr = node.pwr?node.pwr:0;
4212
- if (pwr !== current) {
4213
- if (((view == 1) || (view == 3) || (view == 5)) && (current != null)) { r += '</div>'; } // Close collapse div
4214
- deviceHeaderSet();
4215
- if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
4216
-
4217
- if (view == 2) { r += '<tr><td colspan=' + colcount + '>'; }
4218
- r += '<div class=DevSt style=width:100%;padding-top:4px><span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx style=float:right></span>';
4219
- if ((view == 1) || (view == 2) || (view == 3) || (view == 5)) {
4220
- var collapsed = CollapsedGroups['pwr:' + pwr];
4221
- r += '<img class=collapseImage cmenu=expandAllContextMenu id="DevxColImg' + deviceHeaderId + '" src=images/c' + ((collapsed === true)?'1':'2') + '.png height=8 width=8 style=margin-left:2px;margin-right:2px;cursor:pointer onclick=toggleCollapseGroup("' + deviceHeaderId + '","pwr:' + pwr + '",' + view + ')></img>'; // Collapse action
4222
- }
4223
- r += '<span>' + PowerStateStr2(node.pwr) + '</span></div>';
4224
-
4225
- current = pwr;
4226
- c = 0;
4227
- if ((view == 1) || (view == 3) || (view == 5)) { r += '<div id=DevxCol' + deviceHeaderId + ((collapsed === true)?' style=display:none':'') + '>'; } // Open collapse div
4228
- }
4229
- } else if (sort == 2 || sort == 5) {
4230
- // Device header
4231
- if (current == null) { current = '1'; }
4232
- }
4233
-
4234
- count++;
4235
- if (view == 1) {
4236
- // Draw the device standin
4237
- r += '<div name=xxdevice1 id=xv1' + node._id + ' style=display:inline-block;position:relative;width:' + deviceBoxWidth + 'px;height:50px;padding-top:1px;padding-bottom:1px></div>';
4238
- } else if (view == 2) {
4239
- // Draw the device standin
4240
- var collapseName = node.meshid;
4241
- if (sort == 1) { collapseName = ('pwr:' + (node.pwr?node.pwr:0)); }
4242
- else if ((sort == 3) || (sort == 4)) { collapseName = 'tag:**xx**xx*TaG*xx**xx**'; }
4243
- var collapsed = (sort != 3) & (sort != 4) & CollapsedGroups[collapseName];
4244
- r += '<tr name=xxdevice2 colname=DevxCol' + collapseName + ' style=height:20px' + (collapsed?';display:none':'') + ' id=xv2' + node._id + '></tr>';
4245
- } else if (((view == 3) || (view == 5)) && (node.conn & 1) && (((meshrights & 8) || (meshrights & 256)) != 0) && (node.agent) && ((node.agent.caps & 1) != 0)) { // Check if we have rights and agent is capable of KVM.
4246
- // Draw the device (TODO: See if we can replace this with a standin in the future)
4247
- if ((Object.keys(checkedNodeids).length == 0) || checkedNodeids[node._id]) {
4248
- r += updateDeviceViewHtml(view, null, node);
4249
- kvmDivs.push(node._id);
4250
- }
4251
- }
4252
-
4253
- // If we are displaying devices by tags, put the device in the right tag group.
4254
- if (((sort == 3) || (sort == 4)) && (r != '')) {
4255
- if (node.tags) {
4256
- for (var j in node.tags) {
4257
- var tag = node.tags[j];
4258
- if (sort == 4) { if (mesh2) { tag = mesh2.name + ' - ' + node.tags[j]; } else { tag = '**INDV*~*DEVS** - ' + node.tags[j]; } }
4259
- var collapsed = CollapsedGroups['tag:' + encodeURIComponentEx(tag)];
4260
- var r2 = r.replace('**xx**xx*TaG*xx**xx**', encodeURIComponentEx(tag) + (collapsed?' style=display:none':''));
4261
- if (groups[tag] == null) { groups[tag] = r2; groupCount[tag] = 1; } else { groups[tag] += r2; groupCount[tag] += 1; }
4262
- if ((view == 3) || (view == 5)) break;
4263
- }
4264
- } else {
4265
- // If sorted by "Groups-Tags" and a device has no tags, put in a group only section.
4266
- if ((sort == 4) && (mesh2 != null) && ((node.tags == null) || (node.tags.length == 0))) {
4267
- var tag = mesh2.name;
4268
- var collapsed = CollapsedGroups['tag:' + encodeURIComponentEx(tag)];
4269
- var r2 = r.replace('**xx**xx*TaG*xx**xx**', encodeURIComponentEx(tag) + (collapsed?' style=display:none':''));
4270
- if (groups[tag] == null) { groups[tag] = r2; groupCount[tag] = 1; } else { groups[tag] += r2; groupCount[tag] += 1; }
4271
- }
4272
- }
4273
- r = '';
4274
- }
4275
-
4276
- deviceHeaderTotal++;
4277
- if (typeof deviceHeaderCount[node.state] == 'undefined') { deviceHeaderCount[node.state] = 1; } else { deviceHeaderCount[node.state]++; }
4278
- }
4279
-
4280
- if ((view == 1) && (current != null)) { r += '</div>'; } // Close collapse div
4281
-
4282
- // Above 32 devices, gray out the auto connect feature.
4283
- if (kvmDivs.length >= 32) { Q('autoConnectDesktopCheckbox').checked = false; }
4284
- QE('autoConnectDesktopCheckbox', kvmDivs.length < 32);
4285
-
4286
- // If displaying devices by groups, sort the group names and display the devices.
4287
- if ((sort == 3) || (sort == 4)) {
4288
- var groupNames = [], tagDeviceHeaderId = 0;
4289
- for (var i in groups) { groupNames.push(i); }
4290
- //groupNames.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); });
4291
- groupNames.sort(function (a, b) { return sortCollator.compare(a.toLowerCase(), b.toLowerCase()); });
4292
- for (var j in groupNames) {
4293
- var i = groupNames[j];
4294
- if (view == 2) {
4295
- r += '<tr><td colspan=' + colcount + '><div class=DevSt style=width:100%;padding-top:4px>';
4296
- var collapsed = CollapsedGroups['tag:' + encodeURIComponentEx(i)];
4297
- r += '<img class=collapseImage cmenu=expandAllContextMenu id="DevxColImg' + tagDeviceHeaderId + '" src=images/c' + ((collapsed === true)?'1':'2') + '.png height=8 width=8 style=margin-left:2px;margin-right:2px;cursor:pointer onclick=toggleCollapseGroup("' + tagDeviceHeaderId + '","tag:' + encodeURIComponentEx(i) + '",2)></img>'; // Collapse action
4298
- r += '<span class=devHeaderx style=float:right>' + groupCount[i] + ' node' + ((groupCount[i] > 1) ? 's' : '') + '</span><span>' + EscapeHtml(i).split('|').join(' → ').split('**INDV*~*DEVS**').join('<i>' + "Individual Devices" + '</i>') + '</span></div>' + groups[i];
4299
- } else {
4300
- r += '<div class=DevSt style=width:100%;padding-top:4px><span class=devHeaderx style=float:right>' + format(((groupCount[i] > 1) ? '{0} nodes' : '{0} node'), groupCount[i]) + '</span>';
4301
- var collapsed = CollapsedGroups['tag:' + encodeURIComponentEx(i)];
4302
- r += '<img class=collapseImage cmenu=expandAllContextMenu id="DevxColImg' + tagDeviceHeaderId + '" src=images/c' + ((collapsed === true)?'1':'2') + '.png height=8 width=8 style=margin-left:2px;margin-right:2px;cursor:pointer onclick=toggleCollapseGroup("' + tagDeviceHeaderId + '","tag:' + encodeURIComponentEx(i) + '")></img>'; // Collapse action
4303
- r += '<span>' + EscapeHtml(i).split('|').join(' → ').split('**INDV*~*DEVS**').join('<i>' + "Individual Devices" + '</i>') + '</span></div>';
4304
- r += '<div id=DevxCol' + tagDeviceHeaderId + ((collapsed === true)?' style=display:none':'') + '>' + groups[i] + '</div>'; // Open collapse div
4305
- }
4306
- tagDeviceHeaderId++;
4307
- }
4308
- }
4309
-
4310
- // If there is nothing to display, explain the problem
4311
- var viewNothing = false;
4312
- if ((r == '') && (nodes.length > 0) && ((Q('SearchInput').value != '') || (Q('DevFilterSelect').value != 0))) {
4313
- viewNothing = true;
4314
- if (sort == 3) {
4315
- r = '<div style="margin:30px">' + "No devices are included in any groups, click on a device's \"Groups\" to add to a group." + '</div>';
4316
- } else {
4317
- r = '<div style="margin:30px">' + "No devices matching this search." + ' <a onclick=clearDeviceSearch()>' + "Clear search filter" + '</a></div>';
4318
- }
4319
- }
4320
-
4321
- if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
4322
-
4323
- // Display all empty device groups, we need to do this because users can add devices to these at any time.
4324
- if ((sort == 0) && ((Q('SearchInput').value == '') && (Q('DevFilterSelect').value == 0)) && (view < 3)) {
4325
- var deviceHeaderId2 = deviceHeaderId, sortedMeshes = [];
4326
- for (var i in meshes) { sortedMeshes.push(meshes[i]); }
4327
- sortedMeshes.sort(nameSort);
4328
- for (var i in sortedMeshes) {
4329
- var mesh = sortedMeshes[i], meshrights = GetMeshRights(mesh);
4330
- if (displayedMeshes[mesh._id] == null) {
4331
- if ((current != '') && (r != '')) { r += '</tr></table>'; }
4332
- r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt>';
4333
-
4334
- // Collapsing header & start collapsing area
4335
- deviceHeaderId2++;
4336
- var collapsed = CollapsedGroups[mesh._id];
4337
- r += '<img class=collapseImage cmenu=expandAllContextMenu id="DevxColImg' + deviceHeaderId2 + '" src=images/c' + ((collapsed === true)?'1':'2') + '.png height=8 width=8 style=margin-left:2px;margin-right:2px;cursor:pointer onclick=toggleCollapseGroup("' + deviceHeaderId2 + '","' + mesh._id + '")></img>'; // Collapse action
4338
-
4339
- r += '<span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span><span>';
4340
- r += getMeshActions(mesh, meshrights);
4341
- r += '</span></td></tr><tr>';
4342
- if (mesh.mtype == 1) {
4343
- r += '<td><div style=padding:10px><i>' + "No Intel® AMT devices in this device group";
4344
- if (((meshrights & 4) != 0) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 4096) == 0))) { r += ', <a href=# style=cursor:pointer onclick=\'return addDeviceToMesh("' + mesh._id + '")\'>' + "add one" + '</a>'; }
4345
- } else if (mesh.mtype == 2) {
4346
- r += '<td><div id=DevxCol' + deviceHeaderId2 + ((collapsed === true)?' style=display:none':'') + '>'; // Open collapse div
4347
- r += '<div style=padding:10px><i>' + "No devices in this device group";
4348
- if (((meshrights & 4) != 0) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 4096) == 0))) { r += ', <a href=# style=cursor:pointer onclick=\'return addAgentToMesh("' + mesh._id + '")\'>' + "add one" + '</a>'; }
4349
- } else if (mesh.mtype == 3) {
4350
- r += '<td><div id=DevxCol' + deviceHeaderId2 + ((collapsed === true)?' style=display:none':'') + '>'; // Open collapse div
4351
- r += '<div style=padding:10px><i>' + "No local devices in this device group";
4352
- if (((meshrights & 4) != 0) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 4096) == 0))) { r += ', <a href=# style=cursor:pointer onclick=\'return addLocalDeviceToMesh("' + mesh._id + '")\'>' + "add one" + '</a>'; }
4353
- } else if (mesh.mtype == 4) {
4354
- r += '<td><div id=DevxCol' + deviceHeaderId2 + ((collapsed === true)?' style=display:none':'') + '>'; // Open collapse div
4355
- r += '<div style=padding:10px><i>' + "No devices in this device group";
4356
- }
4357
- r += '.</i></div></td>';
4358
- r += '</div>'; // End collapsing area
4359
-
4360
- current = mesh._id;
4361
- count++;
4362
- }
4363
- }
4364
- }
4365
-
4366
- if ((r != '') && (viewNothing == false)) {
4367
- r += '</table>';
4368
- if (view == 2) {
4369
- var colums = '';
4370
-
4371
- // Use defaults if needed
4372
- if (deviceViewSettings == null) { deviceViewSettings = {}; }
4373
- if (!Array.isArray(deviceViewSettings.devsCols)) { deviceViewSettings.devsCols = ['user','ip','conn']; }
4374
-
4375
- // Display configured columns
4376
- if (deviceViewSettings.devsCols.indexOf('agtype') >= 0) { colums += '<th style=color:gray;width:100px>' + "Agent Type"; }
4377
- if (deviceViewSettings.devsCols.indexOf('agver') >= 0) { colums += '<th style=color:gray;width:100px>' + "Agent Version"; }
4378
- if (deviceViewSettings.devsCols.indexOf('os') >= 0) { colums += '<th style=color:gray;width:160px>' + "OS"; }
4379
- if (deviceViewSettings.devsCols.indexOf('links') >= 0) { colums += '<th style=color:gray;width:120px>' + "Links"; }
4380
- if (deviceViewSettings.devsCols.indexOf('user') >= 0) { colums += '<th style=color:gray;width:120px>' + "User"; }
4381
- if (deviceViewSettings.devsCols.indexOf('ip') >= 0) { colums += '<th style=color:gray;width:120px>' + "Address"; }
4382
- if (deviceViewSettings.devsCols.indexOf('conn') >= 0) { colums += '<th style=color:gray;width:100px>' + "Connectivity"; }
4383
- if (deviceViewSettings.devsCols.indexOf('lastseen') >= 0) {
4384
- colums += '<th style=color:gray;width:120px>' + "Last Seen";
4385
- if (requestedLastConnects == false) { requestedLastConnects = true; meshserver.send({ action: 'lastconnects' }); }
4386
- }
4387
-
4388
- // This height of 1 div at the end to fix a problem in Linux firefox browsers
4389
- r = '<table style=width:100%;margin-top:4px cellpadding=0 cellspacing=0><th style=color:gray>' + colums + r + '</tr></table><div style=height:1px></div>';
4390
- }
4391
- } else {
4392
- r += '</table>';
4393
- if (sort == 3) { r = '<div style="margin:10px"><i>' + "No devices with tags found." + '</i></div>'; }
4394
- }
4395
-
4396
- // Add a "Add Device Group" option
4397
- r += '<div style=border-top-style:solid;border-top-width:1px;border-top-color:#DDDDDD;cursor:pointer;font-size:small;margin-top:4px>';
4398
- if ((view < 3) && (sort == 0) && (Object.keys(meshes).length > 0) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 64) == 0))) {
4399
- r += '<a href=# onclick="return account_createMesh()" title="' + "Create a new group of devices." + '" style=cursor:pointer>' + "Add Device Group" + '</a> ';
4400
- }
4401
- if ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 128) == 0)) {
4402
- r += '<a href=# onclick=\'return p10showMeshCmdDialog(0)\' style=cursor:pointer title="' + "Download MeshCmd, a command line tool that performs many functions." + '">' + "MeshCmd" + '</a> ';
4403
- if ((navigator.platform.toLowerCase() == 'win32') || (navigator.platform.toLowerCase() == 'macintel')) { r += '<a href=# onclick=\'return p10showMeshRouterDialog()\' style=cursor:pointer title="' + "Download MeshCentral Router, a TCP port mapping tool." + '">' + "Router" + '</a> '; }
4404
- }
4405
- r += '</div><br/>';
4406
-
4407
- QH('xdevices', r);
4408
- deviceHeaderSet();
4409
-
4410
- for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
4411
- for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
4412
- p1updateInfo();
4413
-
4414
- // Take care of KVM surfaces in desktop view mode
4415
- if (((view == 3) || (view == 5)) && (xxcurrentView == 1)) {
4416
-
4417
- // Figure out and adjust the size to fill the width of the div
4418
- var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
4419
- if ((view == 3)) { // If we are in fixed width mode, correct the size for the screen width.
4420
- var realw = vsize.x + 2, tw = totalDeviceViewWidth - 5, xw = Math.floor(tw / realw);
4421
- xw = realw + Math.floor((tw - (xw * realw)) / xw);
4422
- vsize.y = vsize.y * (xw / vsize.x);
4423
- vsize.x = xw;
4424
- }
4425
-
4426
- for (var i in multiDesktop) { multiDesktop[i].xxdelete = true; }
4427
- for (var i in kvmDivs) {
4428
- var id = kvmDivs[i], shortid = id.split('/')[2], desk = multiDesktop[id];
4429
- if (desk != null) {
4430
- // This device already has a canvas, use it.
4431
- var width = (view == 5)?((desk.m.width * vsize.y) / desk.m.height):vsize.x;
4432
- desk.m.CanvasId.setAttribute('style', 'background-color:black;width:' + width + 'px;height:' + vsize.y + 'px');
4433
- Q('xkvmid_' + shortid).appendChild(desk.m.CanvasId);
4434
- delete desk.xxdelete;
4435
- QH('skvmid_' + shortid, ["Disconnected", "Connecting...", "Setup...", '', ''][((desk.m.State == null)?desk.m.state:desk.m.State)]);
4436
- } else {
4437
- var node = getNodeFromId(id);
4438
- if ((desktopNode == node) && (desktop != null)) { // Check if the main desktop is this device, if it is, use that.
4439
- // This device already has a canvas, use it.
4440
- var c = desktop.m.CanvasId;
4441
- var width = (view == 5)?((desktop.m.width * vsize.y) / desktop.m.height):vsize.x;
4442
- c.setAttribute('id', 'kvmid_' + shortid);
4443
- c.setAttribute('style', 'background-color:black;width:' + width + 'px;height:' + vsize.y + 'px');
4444
- c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
4445
- c.removeAttribute('onmousedown');
4446
- c.removeAttribute('onmouseup');
4447
- c.removeAttribute('onmousemove');
4448
- Q('xkvmid_' + shortid).appendChild(c);
4449
- QH('skvmid_' + shortid, ["Disconnected", "Connecting...", "Setup...", '', ''][((desktop.m.State == null)?desktop.m.state:desktop.m.State)]);
4450
- if (desktop.m.SendCompressionLevel) { desktop.m.SendCompressionLevel(webpSupport?4:1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
4451
- desktop.shortid = shortid;
4452
- desktop.onStateChanged = onMultiDesktopStateChange;
4453
- desktop.m.onRemoteInputLockChanged = null;
4454
- desktop.m.onKeyboardStateChanged = null;
4455
- multiDesktop[id] = desktop;
4456
- desktop = desktopNode = currentNode = null;
4457
- // Setup a replacement desktop
4458
- QH('DeskParent', '<canvas id="Desk" oncontextmenu="return false" onmousedown=dmousedown(event) onmouseup=dmouseup(event) onmousemove=dmousemove(event)></canvas>');
4459
- } else {
4460
- // This is a new device, create a canvas for it.
4461
- var c = document.createElement('canvas');
4462
- c.setAttribute('id', 'kvmid_' + shortid);
4463
- c.setAttribute('width', 640);
4464
- c.setAttribute('height', 480);
4465
- c.setAttribute('oncontextmenu', 'return false');
4466
- c.setAttribute('style', 'background-color:black;width:' + vsize.x + 'px;height:' + vsize.y + 'px');
4467
- c.setAttribute('onclick', 'toggleKvmDevice(\'' + id + '\')');
4468
- try { Q('xkvmid_' + shortid).appendChild(c); } catch (ex) {}
4469
- // Check if we need to auto-connect
4470
- if (Q('autoConnectDesktopCheckbox').checked == true) { setTimeout(function() { connectMultiDesktop(node, 1); }, 100); }
4471
- }
4472
- }
4473
- }
4474
- for (var i in multiDesktop) {
4475
- // If a device is no longer viewed, disconnect it.
4476
- if (multiDesktop[i].xxdelete == true) { multiDesktop[i].Stop(); delete multiDesktop[i]; }
4477
- else if (debugmode && multiDesktop[i].m && multiDesktop[i].m.onScreenSizeChange) {
4478
- mdeskAdjust(multiDesktop[i].m, multiDesktop[i].m.ScreenWidth, multiDesktop[i].m.ScreenHeight, multiDesktop[i].m.CanvasId); // Adjust screen size change
4479
- }
4480
- }
4481
- deskAdjust();
4482
- } else {
4483
- disconnectAllKvmFunction();
4484
- Q('autoConnectDesktopCheckbox').checked = false;
4485
- }
4486
- }
4487
- oldviewmode = view;
4488
- onDevicesScrollEx();
4489
- }
4490
-
4491
-
4492
- var onDevicesTouchActive = false;
4493
- var onDevicesScrollnagleTimer = null;
4494
- function onDevicesScroll() {
4495
- if ((onDevicesScrollnagleTimer != null) || (onDevicesTouchActive)) return;
4496
- onDevicesScrollnagleTimer = setTimeout(onDevicesScrollEx, 250);
4497
- }
4498
-
4499
- function onDeviceTouch(x) {
4500
- if (onDevicesTouchActive == x) return;
4501
- onDevicesTouchActive = x;
4502
- if (x == false) onDevicesScrollEx();
4503
- }
4504
-
4505
- function onDevicesScrollEx() {
4506
- if (onDevicesScrollnagleTimer != null) { clearTimeout(onDevicesScrollnagleTimer); onDevicesScrollnagleTimer = null; }
4507
- var visibleTop = Q('xdevices').scrollTop - 200, visibleBottom = Q('xdevices').scrollTop + Q('xdevices').clientHeight + 200;
4508
- var view = Q('viewselect').value, devdivs = document.getElementsByName('xxdevice' + view);
4509
- for (var i = 0; i < devdivs.length; i++) {
4510
- if ((devdivs[i].offsetTop >= visibleTop) && (devdivs[i].offsetTop < visibleBottom)) {
4511
- var node = getNodeFromId(devdivs[i].id.substring(3));
4512
- if (node != null) { updateDeviceViewHtml(view, devdivs[i], node); } else { devdivs[i].innerHTML = ''; }
4513
- } else {
4514
- devdivs[i].innerHTML = '';
4515
- }
4516
- }
4517
- }
4518
-
4519
- // Update a single device in the current view
4520
- function updateDeviceViewDevice(node) {
4521
- var view = Q('viewselect').value;
4522
- if ((view != 1) && (view != 2)) { mainUpdate(4); return; }
4523
- if (typeof node == 'string') { node = getNodeFromId(node); }
4524
- if (node == null) return;
4525
- var devdiv = Q('xv' + view + node._id);
4526
- if ((devdiv != null) && (devdiv.innerHTML != '')) { updateDeviceViewHtml(view, devdiv, node); } // Only update if the device is visible
4527
- }
4528
-
4529
- function updateDeviceViewHtml(view, div, node) {
4530
- var title = EscapeHtml(node.name);
4531
- if (title.length == 0) { title = '<i>' + "None" + '</i>'; }
4532
- if ((node.rname != null) && (node.rname.length > 0)) { title += ' / ' + EscapeHtml(node.rname); }
4533
- var name = EscapeHtml(node.name);
4534
- if (showRealNames == true && node.rname != null) name = EscapeHtml(node.rname);
4535
- if (name.length == 0) { name = '<i>' + "None" + '</i>'; }
4536
- if (((view == 1) && (div.parentNode.style['display'] == 'none')) || ((view == 2) && (div.style['display'] == 'none'))) { div.innerHTML = ''; return; } // If this section is collapsed, don't render
4537
-
4538
- // Add device notification icons
4539
- var devNotify = '', devNotifySub = '';
4540
-
4541
- // This device is "starred"
4542
- if (stars[node._id] == 1) {
4543
- if (view == 2) {
4544
- devNotifySub += '<img class=deviceNotifySmallDotSub src=images/icon-star-notify-10.png width=10 height=10>';
4545
- } else {
4546
- devNotifySub += '<img class=deviceNotifyDotSub src=images/icon-star-notify-16.png width=16 height=16>';
4547
- }
4548
- }
4549
-
4550
- // This device has session information
4551
- if (node.sessions != null) {
4552
- // Display any agent messages
4553
- if (node.sessions.msg != null) {
4554
- if (view == 2) {
4555
- devNotifySub += '<div onclick=showDeviceMessages(\'' + node._id + '\',null,event) style="width:10;height:10" class=deviceNotifySmallDotSub></div>';
4556
- } else {
4557
- devNotifySub += '<div onclick=showDeviceMessages(\'' + node._id + '\',null,event) style="width:16;height:16" class=deviceNotifyDotSub>' + Object.keys(node.sessions.msg).length + '</div>';
4558
- }
4559
- }
4560
-
4561
- // Sessions are active
4562
- if ((node.sessions.kvm != null) || (node.sessions.terminal != null) || (node.sessions.files != null) || (node.sessions.tcp != null) || (node.sessions.udp != null)) {
4563
- if (view == 2) {
4564
- devNotifySub += '<img onclick=showDeviceSessions(\'' + node._id + '\',null,event) class=deviceNotifySmallDotSub src=images/icon-relay-notify10.png width=10 height=10>';
4565
- } else {
4566
- devNotifySub += '<img onclick=showDeviceSessions(\'' + node._id + '\',null,event) class=deviceNotifyDotSub src=images/icon-relay-notify.png width=16 height=16>';
4567
- }
4568
- }
4569
-
4570
- // Help is required
4571
- if (node.sessions.help != null) {
4572
- if (view == 2) {
4573
- devNotifySub += '<img onclick=showDeviceHelpRequests(\'' + node._id + '\',null,event) class=deviceNotifySmallDotSub src=images/icon-help-notify-10.png width=10 height=10>';
4574
- } else {
4575
- devNotifySub += '<img onclick=showDeviceHelpRequests(\'' + node._id + '\',null,event) class=deviceNotifyDotSub src=images/icon-help-notify-16.png width=16 height=16>';
4576
- }
4577
- }
4578
-
4579
- // Battery state
4580
- if ((node.sessions.battery != null) && (view == 1)) {
4581
- var bat = node.sessions.battery;
4582
- var statestr = '';
4583
- if (bat.state == 'ac') { statestr = "Device is plugged-in"; }
4584
- if (bat.state == 'dc') { statestr = "Device is battery powered"; }
4585
-
4586
- var levelstr = '', levelnum = -1;
4587
- if ((typeof bat.level == 'number') && (bat.level >= 0) && (bat.level <= 100)) {
4588
- levelstr = bat.level + '%';
4589
- levelnum = (Math.floor((bat.level + 10) / 25) + 1);
4590
- if (levelnum > 5) { lvl = 5; }
4591
- if (bat.state == 'ac') { if (bat.level == 100) { levelnum = 11; } else { levelnum += 5; } }
4592
- }
4593
-
4594
- if (levelnum > 0) {
4595
- devNotify += '<div class="deviceBatterySmall deviceBatterySmall' + levelnum + '" title="' + ((statestr != null)?(statestr + ', ' + levelstr):levelstr) + '"></div>';
4596
- }
4597
- }
4598
- }
4599
-
4600
- // Add any device icons
4601
- if (devNotifySub != '') {
4602
- if (view == 2) {
4603
- devNotify += '<div class=deviceNotifySmallDot>' + devNotifySub + '</div>';
4604
- } else {
4605
- devNotify += '<div class=deviceNotifyDot>' + devNotifySub + '</div>';
4606
- }
4607
- }
4608
-
4609
- // Node
4610
- var icon = node.icon;
4611
- if (((!node.conn) || (node.conn == 0)) && (node.mtype != 3)) { icon += ' gray'; }
4612
-
4613
- if (view == 1) {
4614
- div.innerHTML = '<table id=devs cmenu=devsContentMenu onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=width:100%;height:100%><tr><td style=width:22px><input class="' + node.meshid + ' DeviceCheckbox" onchange=p1devcheck(event) value=devid_' + node._id + ' type=checkbox ' + (checkedNodeids[node._id]?' checked':'') + '></td><td><table onclick=gotoDevice(\'' + node._id + '\',null,null,event) border=0 cellspacing=0 style=width:100%;height:100%;cursor:pointer><tr><td style=width:50px tabindex=0 onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',null,null,event)"><div class="i' + icon + '" style=width:50px></div></td><td class=g1t></td><td class=e2t><div class=e1t style=width:' + ((div.clientWidth) - 120) + 'px title="' + title + '">' + name + '</div><div>' + NodeStateStr(node) + '</div></td><td class=g2t></td></tr></table></td></tr></table>' + devNotify;
4615
- } else if (view == 2) {
4616
- var states = [];
4617
- if (node.conn) {
4618
- if ((node.conn & 1) != 0) {
4619
- if (node.mtype == 4) {
4620
- if (node.porttype == 'PDU') {
4621
- states.push('<span title="' + "Switch port is ready for use." + '">' + "Switch" + '</span>');
4622
- } else {
4623
- states.push('<span title="' + "IP-KVM port is connected and ready for use." + '">' + "IP-KVM" + '</span>');
4624
- }
4625
- } else {
4626
- states.push('<span title="' + "Mesh agent is connected and ready for use." + '">' + "Agent" + '</span>');
4627
- }
4628
- }
4629
- if ((node.conn & 2) != 0) { states.push('<span title="' + "Intel® AMT CIRA is connected and ready for use." + '">' + "CIRA" + '</span>'); }
4630
- else if ((node.conn & 4) != 0) { states.push('<span title="' + "Intel® AMT is routable." + '">' + "AMT" + '</span>'); }
4631
- if ((node.conn & 8) != 0) { states.push('<span title="' + "Mesh agent is reachable using another agent as relay." + '">' + "Relay" + '</span>'); }
4632
- if ((node.conn & 16) != 0) { states.push('<span title="' + "MQTT connection to the device is active." + '">' + "MQTT" + '</span>'); }
4633
- }
4634
- if (node.mtype == 3) {
4635
- var mesh = meshes[node.meshid];
4636
- if (mesh && mesh.relayid) {
4637
- states.push('<span title="' + "Local network connection thru a relay agent." + '">' + "Relay" + '</span>');
4638
- } else {
4639
- states.push('<span title="' + "Local network connection." + '">' + "Local" + '</span>');
4640
- }
4641
- }
4642
-
4643
- if (node.desc && (deviceViewSettings.devsCols.indexOf('desc') >= 0)) { name = '<div style=float:right>' + EscapeHtml(node.desc) + '</div><div>' + name + '</div>'; }
4644
-
4645
- var collapseName = node.meshid;
4646
- if (sort == 1) { collapseName = ('pwr:' + (node.pwr?node.pwr:0)); }
4647
- else if ((sort == 3) || (sort == 4)) { collapseName = 'tag:**xx**xx*TaG*xx**xx**'; }
4648
- var collapsed = (sort != 3) & (sort != 4) & CollapsedGroups[collapseName];
4649
- var r = '<td style=position:relative><div id=devs cmenu=devsContentMenu class=bar18 tabindex=0 onmouseover=devMouseHover(this,1) onmouseout=devMouseHover(this,0) style=height:18px;width:100%;font-size:medium onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',null,null,event)">';
4650
- r += '<div class=deviceBarCheckbox><input class="' + node.meshid + ' DeviceCheckbox" value=devid_' + node._id + ' type=checkbox onchange=p1devcheck(event) ' + (checkedNodeids[node._id]?' checked':'') + '></div>';
4651
- r += '<div class=deviceBarIcon onclick=gotoDevice(\'' + node._id + '\',null,null,event)><div class="j' + icon + '" style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
4652
- r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
4653
- r += '<div class=style10 style=cursor:pointer;font-size:14px;max-height:18px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap title="' + title + '" onclick=gotoDevice(\'' + node._id + '\',null,null,event)>' + name + '</div></div>' + devNotify + '</td>';
4654
-
4655
- // Use defaults if needed
4656
- if (deviceViewSettings == null) { deviceViewSettings = {}; }
4657
- if (!Array.isArray(deviceViewSettings.devsCols)) { deviceViewSettings.devsCols = ['user','ip','conn']; }
4658
-
4659
- // Display configured columns
4660
- if (deviceViewSettings.devsCols.indexOf('agtype') >= 0) { r += '<td style=text-align:center;font-size:x-small;padding-left:4px;padding-right:4px title="' + EscapeHtml(((node.mtype != 3) && node.agent && node.agent.id && (node.agent.id <= agentsStr.length))?agentsStr[node.agent.id]:'') + '">' + EscapeHtml(((node.mtype != 3) && node.agent && node.agent.id && (node.agent.id <= agentsStr.length))?agentsStr[node.agent.id]:'').replace(',', '<br />'); } // Agent type
4661
- if (deviceViewSettings.devsCols.indexOf('agver') >= 0) { r += '<td style=text-align:center;font-size:x-small;padding-left:4px;padding-right:4px title="' + EscapeHtml((node.agent && node.agent.core)?node.agent.core:'') + '">' + EscapeHtml((node.agent && node.agent.core)?node.agent.core:'').replace(',', '<br />'); } // Agent core
4662
- if (deviceViewSettings.devsCols.indexOf('os') >= 0) { // Operating System
4663
- if (node.mtype == 3) {
4664
- var osstr = ''; if (node.agent.id == 4) { osstr = 'Windows'; } if (node.agent.id == 6) { osstr = 'Linux'; } if (node.agent.id == 29) { osstr = 'MacOS'; }
4665
- r += '<td style=text-align:center;font-size:x-small title="' + EscapeHtml(osstr) + '">' + EscapeHtml(osstr);
4666
- } else {
4667
- r += '<td style=text-align:center;font-size:x-small title="' + EscapeHtml(node.osdesc?node.osdesc:'') + '">' + EscapeHtml(node.osdesc?node.osdesc:'');
4668
- }
4669
- }
4670
- if (deviceViewSettings.devsCols.indexOf('links') >= 0) { r += '<td style=text-align:center;font-size:x-small>' + getShortRouterLinks(node); } // Links
4671
- if (deviceViewSettings.devsCols.indexOf('user') >= 0) { r += '<td style=text-align:center>' + getUserShortStr(node); } // User
4672
- if (deviceViewSettings.devsCols.indexOf('ip') >= 0) { var ip = ''; if (node.mtype == 3) { ip = node.host; } else if (node.ip) { ip = node.ip; } r += '<td style=text-align:center>' + ip; } // IP address
4673
- if (deviceViewSettings.devsCols.indexOf('conn') >= 0) { r += '<td style=text-align:center>' + states.join(' + '); } // Connectivity
4674
- if (deviceViewSettings.devsCols.indexOf('lastseen') >= 0) { r += '<td style=text-align:center;font-size:x-small>'; if (node.conn > 0) { r += "Connected"; } else if (node.lastconnect != null) { r += printDateTime(new Date(node.lastconnect)); } }
4675
-
4676
- div.innerHTML = r;
4677
- } else if ((view == 3) || (view == 5)) {
4678
- // Draw the device and canvas
4679
- var r = '<div id=devs cmenu=devsContentMenu style=display:inline-block;position:relative;margin:1px;background-color:lightgray;border-radius:5px;position:relative><div tabindex=0 style=padding:3px;cursor:pointer onclick=gotoDevice(\'' + node._id + '\',11,null,event) onkeypress="if (event.key==\'Enter\') gotoDevice(\'' + node._id + '\',11,null,event)">' + devNotify;
4680
- //r += '<input class="' + node.meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + node._id + ' type=checkbox style=float:left>';
4681
- r += '<div class="j' + icon + '" style=width:16px;float:left></div> ' + name + '</div>';
4682
- r += '<span onclick=gotoDevice(\'' + node._id + '\',null,null,event)></span><div id=xkvmid_' + node._id.split('/')[2] + '><div id=skvmid_' + node._id.split('/')[2] + ' tabindex=0 style="position:absolute;color:white;left:5px;top:27px;text-shadow:0px 0px 5px #000;z-index:10;cursor:default" onclick=toggleKvmDevice(\'' + node._id + '\') onkeypress="if (event.key==\'Enter\') toggleKvmDevice(\'' + node._id + '\')">' + "Disconnected" + '</div></div>';
4683
- r += '</div>';
4684
- return r;
4685
- }
4686
- }
4687
-
4688
- // Return HTML with a list of MeshCentral Router links
4689
- function getShortRouterLinks(node) {
4690
- var x = '', meshrights = GetNodeRights(node);
4691
-
4692
- // RDP link, show this link only of the remote machine is Windows.
4693
- if ((((node.conn & 1) != 0) || (node.mtype == 3)) && (node.agent) && ((meshrights & 8) != 0) && (node.agent.id != 14)) {
4694
- if (webRelayPort != 0) {
4695
- x += '<a href=# onclick=p10WebRouter("' + node._id + '",1,' + (node.httpport ? node.httpport : 80) + ')>' + "HTTP" + ((node.httpport && (node.httpport != 80)) ? '/' + node.httpport : '') + '</a> ';
4696
- x += '<a href=# onclick=p10WebRouter("' + node._id + '",2,' + (node.httpsport ? node.httpsport : 443) + ')>' + "HTTPS" + ((node.httspport && (node.httpsport != 443)) ? '/' + node.httpsport : '') + '</a> ';
4697
- }
4698
- if ((node.agent.id > 0) && (node.agent.id < 5)) {
4699
- if (navigator.platform.toLowerCase() == 'win32') {
4700
- if ((serverinfo.devicemeshrouterlinks == null) || (serverinfo.devicemeshrouterlinks.rdp != false)) {
4701
- x += '<a href=# cmenu=altPortContextMenu id=rdpMCRouterLink onclick=p10MCRouter("' + node._id + '",3)>' + "RDP" + '</a> ';
4702
- }
4703
- }
4704
- }
4705
- if (node.agent.id > 4) {
4706
- if ((navigator.platform.toLowerCase() == 'win32') || (navigator.platform.toLowerCase() == 'macintel')) {
4707
- if ((serverinfo.devicemeshrouterlinks == null) || (serverinfo.devicemeshrouterlinks.ssh != false)) {
4708
- x += '<a href=# onclick=p10MCRouter("' + node._id + '",4,' + (node.sshport ? node.sshport : 22) + ')>' + "SSH" + '</a> ';
4709
- }
4710
- }
4711
- if (navigator.platform.toLowerCase() == 'win32') {
4712
- if ((serverinfo.devicemeshrouterlinks == null) || (serverinfo.devicemeshrouterlinks.scp != false)) {
4713
- x += '<a href=# onclick=p10MCRouter("' + node._id + '",5,' + (node.sshport ? node.sshport : 22) + ')>' + "SCP" + '</a> ';
4714
- }
4715
- }
4716
- }
4717
- if ((navigator.platform.toLowerCase() == 'win32') || (navigator.platform.toLowerCase() == 'macintel')) {
4718
- if ((serverinfo.devicemeshrouterlinks != null) && (Array.isArray(serverinfo.devicemeshrouterlinks.extralinks))) {
4719
- for (var i in serverinfo.devicemeshrouterlinks.extralinks) {
4720
- var r = serverinfo.devicemeshrouterlinks.extralinks[i], p = '\"' + r.protocol + '\"';
4721
- if (doesDeviceMatchFilterTags(node, r.filter)) {
4722
- if ((node.mtype == 3) && ((r.protocol == 'mcrdesktop') || (r.protocol == 'mcrfiles'))) continue;
4723
- if (typeof r.protocol == 'number') { p = r.protocol; } else if (r.protocol == 'http') { p = 1; } else if (r.protocol == 'https') { p = 2; } else if (r.protocol == 'rdp') { p = 3; } else if (r.protocol == 'ssh') { p = 4; } else if (r.protocol == 'scp') { p = 5; } else if (r.protocol == 'mcrdesktop') { p = 6; } else if (r.protocol == 'mcrfiles') { p = 7; }
4724
- x += '<a href=# onclick=p10MCRouter("' + node._id + '",' + p + ',' + r.port + (r.ip?(',\"' + r.ip + '\"'):',null') + ',' + (r.localport?r.localport:0) + ')>' + r.name + '</a> ';
4725
- }
4726
- }
4727
- }
4728
- }
4729
- }
4730
-
4731
- return x;
4732
- }
4733
-
4734
- // Check if this device matches any of the given filters
4735
- function doesDeviceMatchFilterTags(node, filter) {
4736
- if (filter == null) return true; // No filters, every device matches.
4737
- if (!Array.isArray(filter)) return false; // Bad filter
4738
- if (filter.indexOf(node.meshid) >= 0) return true; // Device group match
4739
- if (filter.indexOf(node._id) >= 0) return true; // Nodeid match
4740
- if (Array.isArray(node.tags)) { for (var i in node.tags) { if (filter.indexOf('tag:' + node.tags[i]) >= 0) return true; } } // Tag match
4741
- return false;
4742
- }
4743
-
4744
- // Show device help requests
4745
- function showDeviceHelpRequests(nodeid, force, e) {
4746
- if (e) haltEvent(e);
4747
- if (xxdialogMode && !force) return false;
4748
- var node = null, x = '';
4749
- if (nodeid == null) { node = currentNode; } else { node = getNodeFromId(nodeid); }
4750
- if ((node == null) || (node.sessions == null)) { setDialogMode(0); return false; }
4751
- if (node.sessions.help != null) { for (var j in node.sessions.help) { x += '<div style="background-color:#CCC;padding:6px;border-radius:6px"><a style="float:right" onclick=closeDeviceHelpRequest("' + encodeURIComponentEx(j) + '","' + encodeURIComponentEx(node._id) + '")>' + "Dismiss" + '</a><div style=margin-bottom:6px><b>' + EscapeHtml(j) + '</b></div><div style=margin-bottom:6px>' + EscapeHtml(node.sessions.help[j]) + '</div></div>'; } }
4752
- if (x != '') { setDialogMode(2, "Help Requests" + ' - ' + EscapeHtml(node.name), 1, null, x, 'HELPREQ-' + node._id); } else { setDialogMode(0); }
4753
- return false;
4754
- }
4755
-
4756
- function closeDeviceHelpRequest(appid, nodeid) {
4757
- setDialogMode(0);
4758
- meshserver.send({ action: 'msg', type: 'localapp', nodeid: decodeURIComponent(nodeid), appid: decodeURIComponent(appid), value: { cmd: "cancelhelp" } });
4759
- }
4760
-
4761
- // Show currently active sessions on this device
4762
- function showDeviceSessions(nodeid, force, e) {
4763
- if (e) haltEvent(e);
4764
- if (xxdialogMode && !force) return false;
4765
- var node = null, x = '';
4766
- if (nodeid == null) { node = currentNode; } else { node = getNodeFromId(nodeid); }
4767
- if ((node == null) || (node.sessions == null)) { setDialogMode(0); return false; }
4768
- for (var i in node.sessions) {
4769
- if ((i == 'kvm') && (node.sessions.multidesk == null)) {
4770
- x += '<u>' + "Remote Desktop" + '</u>';
4771
- for (var j in node.sessions.kvm) {
4772
- if (j.startsWith('user/')) {
4773
- var trash = '';
4774
- if (((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF))) { trash = ' <a href=# onclick=\'return endDeviceSession("kvm", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4775
- x += addHtmlValue2(getUserName(j), ((node.sessions.kvm[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.kvm[j]))) + trash);
4776
- } else if (j == 'busy') {
4777
- x += addHtmlValue2("Device is busy", ((node.sessions.kvm[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.kvm[j]))));
4778
- }
4779
- }
4780
- } else if (i == 'multidesk') {
4781
- x += '<u>' + "Remote Desktop" + '</u>';
4782
- for (var j in node.sessions.multidesk) {
4783
- var trash = '';
4784
- if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("multidesk", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4785
- x += addHtmlValue2(getUserName(j), ((node.sessions.multidesk[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.multidesk[j]))) + trash);
4786
- }
4787
- } else if (i == 'terminal') {
4788
- x += '<u>' + "Terminal" + '</u>';
4789
- for (var j in node.sessions.terminal) {
4790
- var trash = '';
4791
- if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("terminal", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4792
- x += addHtmlValue2(getUserName(j), ((node.sessions.terminal[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.terminal[j]))) + trash);
4793
- }
4794
- } else if (i == 'files') {
4795
- x += '<u>' + "Files" + '</u>';
4796
- for (var j in node.sessions.files) {
4797
- var trash = '';
4798
- if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("files", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4799
- x += addHtmlValue2(getUserName(j), ((node.sessions.files[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.files[j]))) + trash);
4800
- }
4801
- } else if (i == 'tcp') {
4802
- x += '<u>' + "TCP Routing" + '</u>';
4803
- for (var j in node.sessions.tcp) {
4804
- var trash = '';
4805
- if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("tcp", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4806
- x += addHtmlValue2(getUserName(j), ((node.sessions.tcp[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.tcp[j]))) + trash);
4807
- }
4808
- } else if (i == 'udp') {
4809
- x += '<u>' + "UDP Routing" + '</u>';
4810
- for (var j in node.sessions.udp) {
4811
- var trash = '';
4812
- if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("udp", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4813
- x += addHtmlValue2(getUserName(j), ((node.sessions.udp[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.udp[j]))) + trash);
4814
- }
4815
- }
4816
- }
4817
- if (x != '') { setDialogMode(2, "Sessions" + ' - ' + EscapeHtml(node.name), 1, null, x, 'SESSIONS-' + node._id); } else { setDialogMode(0); }
4818
- return false;
4819
- }
4820
-
4821
- function endDeviceSession(protocol, nodeid, userid) {
4822
- var userIdSplit = decodeURIComponent(userid).split('/'), uid = userIdSplit[0] + '/' + userIdSplit[1] + '/' + userIdSplit[2], guestname = null;
4823
- if ((userIdSplit.length == 4) && (userIdSplit[3].startsWith('guest:'))) { guestname = atob(userIdSplit[3].substring(6)); }
4824
- if (protocol == 'multidesk') {
4825
- meshserver.send({ action: 'endDesktopMultiplex', nodeid: decodeURIComponent(nodeid), xuserid: uid, guestname, guestname });
4826
- } else {
4827
- meshserver.send({ action: 'msg', type: 'endtunnel', nodeid: decodeURIComponent(nodeid), xuserid: uid, guestname, guestname, protocol: protocol });
4828
- }
4829
- }
4830
-
4831
- // Show currently active sessions on this device
4832
- function showDeviceMessages(nodeid, force, e) {
4833
- if (e) haltEvent(e);
4834
- if (xxdialogMode && !force) return false;
4835
- var node = null, x = '<div style=max-height:200px;overflow-y:auto>', count = 0;
4836
- if (nodeid == null) { node = currentNode; } else { node = getNodeFromId(nodeid); }
4837
- if ((node == null) || (node.sessions == null) || (node.sessions.msg == null)) { setDialogMode(0); return false; }
4838
- for (var i in node.sessions.msg) {
4839
- var msg = i, icon = 5;
4840
- if (typeof node.sessions.msg[i].msg == 'string') { msg = node.sessions.msg[i].msg; }
4841
- if ((typeof node.sessions.msg[i].msgid == 'number') && (eventsMessageId[node.sessions.msg[i].msgid] != null)) { msg = eventsMessageId[node.sessions.msg[i].msgid]; }
4842
- if (typeof node.sessions.msg[i].icon == 'number') { icon = node.sessions.msg[i].icon; }
4843
- if ((icon < 1) || (icon > 9)) { icon = 5; }
4844
- x += '<table style=width:96%><td style=width:24px><div class=NotifyIconSmall' + icon + '></div><td><div style="border-radius:5px;background-color:#BBB;width:100%;padding:8px">' + EscapeHtml(msg) + '</div></table>';
4845
- count++;
4846
- }
4847
- x += '</div>';
4848
- if (count > 0) setDialogMode(2, "Agent Messages" + ' - ' + EscapeHtml(node.name), 1, null, x, 'MESSAGES-' + node._id);
4849
- return false;
4850
- }
4851
-
4852
- function toggleCollapseGroup(id, id2, type) {
4853
- var x;
4854
- if (type == 2) {
4855
- // Table rows collapse
4856
- var xrows = document.getElementsByName('xxdevice2');
4857
- if (xrows.length == 0) return;
4858
- var rows = [];
4859
- for (var i = 0; i < xrows.length; i++) { if (xrows[i].attributes.colname.value.substring(7) == id2) { rows.push(xrows[i]); } }
4860
- var x = (rows[0].style['display'] == 'none');
4861
- if (x) { delete CollapsedGroups[id2]; } else { CollapsedGroups[id2] = true; }
4862
- for (var i = 0; i < rows.length; i++) { rows[i].style['display'] = (x ? '' : 'none'); }
4863
- } else {
4864
- // Simple DIV collapse
4865
- x = (QS('DevxCol' + id)['display'] == 'none');
4866
- if (x) { delete CollapsedGroups[id2]; } else { CollapsedGroups[id2] = true; }
4867
- QV('DevxCol' + id, x);
4868
- }
4869
- Q('DevxColImg' + id).src = x?'images/c2.png':'images/c1.png';
4870
- putstore('_collapse', JSON.stringify(CollapsedGroups));
4871
- updateCollapseAllButton();
4872
- onDevicesScrollEx();
4873
- onDevicesScrollEx(); // TODO: Not sure why, but second call is needed for proper update
4874
- }
4875
-
4876
- function toggleKvmDevice(node) {
4877
- if (typeof node == 'string') { node = getNodeFromId(node); } // Convert nodeid to node if needed
4878
- var rights = GetNodeRights(node);
4879
- if ((rights & 8) || (rights & 256)) { // Requires remote control rights or desktop view only rights
4880
- //var conn = 0;
4881
- //if ((node.conn & 1) != 0) { conn = 1; } else if ((node.conn & 6) != 0) { conn = 2; } // Check what type of connect we can do (Agent vs AMT)
4882
- if (node.conn & 1) { connectMultiDesktop(node, 1); }
4883
- }
4884
- }
4885
-
4886
- function getUserShortStr(node) {
4887
- if (node == null || node.users == null || (!Array.isArray(node.users)) || node.users.length == 0) return '';
4888
- if (node.users.length > 1) { return '<span title="' + EscapeHtml(node.users.join(', ')) + '">' + nobreak(format("{0} users", node.users.length)) + '</span>'; }
4889
- var u = node.users[0], su = u, i = u.indexOf('\\');
4890
- if (i > 0) { su = u.substring(i + 1); }
4891
- su = EscapeHtml(su);
4892
- if (su.length > 15) { su = su.substring(0, 14) + '…'; }
4893
- return '<span title="' + EscapeHtml(u) + '">' + su + '</span>';
4894
- }
4895
-
4896
- function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
4897
- function connectAllKvmFunction(force) {
4898
- if (xxdialogMode) return false;
4899
- if (force !== true) { // We need to count how many devices will need to be connected, if it's a lot, prompt first.
4900
- var count = 0;
4901
- for (var i in nodes) {
4902
- var node = nodes[i], nodeid = nodes[i]._id;
4903
- if ((multiDesktop[nodeid] == null) && ((Object.keys(checkedNodeids).length == 0) || checkedNodeids[nodeid])) {
4904
- var rights = GetNodeRights(node);
4905
- if ((rights & 8) || (rights & 256)) { // Requires remote control rights or desktop view only rights
4906
- //var conn = 0;
4907
- //if ((node.conn & 1) != 0) { conn = 1; } else if ((node.conn & 6) != 0) { conn = 2; } // Check what type of connect we can do (Agent vs AMT)
4908
- if ((node.conn & 1) && (node.v == true)) { count++; }
4909
- }
4910
- }
4911
- }
4912
- if (count > 8) { setDialogMode(2, "Connect All", 3, function() { connectAllKvmFunction(true); }, format("Are you sure you want to connect to {0} devices?", count)); return; }
4913
- }
4914
-
4915
- // Perform connect all
4916
- for (var i in nodes) {
4917
- if ((nodes[i].v == true) && (multiDesktop[nodes[i]._id] == null) && ((Object.keys(checkedNodeids).length == 0) || checkedNodeids[nodes[i]._id])) {
4918
- toggleKvmDevice(nodes[i]._id);
4919
- }
4920
- }
4921
- }
4922
- function disconnectAllKvmFunction() { if (xxdialogMode) return false; for (var nodeid in multiDesktop) { multiDesktop[nodeid].Stop(); } multiDesktop = {}; }
4923
- function onMultiDesktopStateChange(desk, state) { try { QH('skvmid_' + desk.shortid, ["Disconnected", "Connecting...", "Setup...", '', ''][state]); } catch (ex) {} }
4924
- function onDeviceSearchChanged(e) { if (e != null) { if (e.target.id == 'SearchInput') { Q('KvmSearchInput').value = Q('SearchInput').value; } else { Q('SearchInput').value = Q('KvmSearchInput').value; } } mainUpdate(5); }
4925
-
4926
- function showMultiDesktopSettings() {
4927
- QV('td7amtkvm', false);
4928
- QV('td7meshkvm', true);
4929
- QV('td7rdpkvm', false);
4930
- QV('d7desktopOtherSettings', false);
4931
- d7bitmapquality.value = multidesktopsettings.quality;
4932
- d7bitmapscaling.value = multidesktopsettings.scaling;
4933
- if (multidesktopsettings.framerate) { d7framelimiter.value = multidesktopsettings.framerate; } else { d7framelimiter.value = 100; }
4934
- setDialogMode(7, "Remote Desktop Settings", 3, showMultiDesktopSettingsChanged);
4935
- }
4936
-
4937
- function showMultiDesktopSettingsChanged() {
4938
- multidesktopsettings.quality = d7bitmapquality.value;
4939
- multidesktopsettings.scaling = d7bitmapscaling.value;
4940
- multidesktopsettings.framerate = d7framelimiter.value;
4941
- localStorage.setItem('multidesktopsettings', JSON.stringify(multidesktopsettings));
4942
- // Make changes to all current connections
4943
- for (var i in multiDesktop) { multiDesktop[i].m.SendCompressionLevel(webpSupport?4:1, multidesktopsettings.quality, multidesktopsettings.scaling, multidesktopsettings.framerate); }
4944
- }
4945
-
4946
- function connectMultiDesktop(node, contype) {
4947
- var nodeid = node._id, shortid = nodeid.split('/')[2];
4948
- var desk = multiDesktop[nodeid];
4949
- if (desk == null) {
4950
- if (Q('kvmid_' + shortid) == null) return; // Check if this device is being displayed, if not, exit now.
4951
- if (contype == 2) {
4952
- // Setup the Intel AMT remote desktop
4953
- if ((node.intelamt.user == null) || (node.intelamt.user == '')) { return; }
4954
- desk = CreateAmtRedirect(CreateAmtRemoteDesktop('kvmid_' + shortid), authCookie);
4955
- desk.shortid = shortid;
4956
- //desk.debugmode = debugmode;
4957
- desk.onStateChanged = onMultiDesktopStateChange;
4958
- desk.m.bpp = 1;
4959
- desk.m.useZRLE = true;
4960
- desk.m.showmouse = true;
4961
- desk.m.onKvmData = function (data) { console.log('KVM Data received in multi-desktop mode, this is not supported.'); }; // KVM Data Channel not supported in multi-desktop right now.
4962
- desk.m.onScreenSizeChange = mdeskAdjust; // Multi-Desktop Adjust
4963
- desk.Start(nodeid, 16994, '*', '*', 0);
4964
- desk.contype = 2;
4965
- multiDesktop[nodeid] = desk;
4966
- } else if (contype == 1) {
4967
- // Setup the Mesh Agent remote desktop
4968
- desk = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('kvmid_' + shortid), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
4969
- desk.m.UseExtendedKeyFlag = (node.agent.id < 5); // Only use extended keys on Windows agents for now
4970
- desk.m.mouseCursorActive(xxcurrentView == 11);
4971
- desk.shortid = shortid;
4972
- desk.attemptWebRTC = attemptWebRTC;
4973
- desk.onStateChanged = onMultiDesktopStateChange;
4974
- //desk.onConsoleMessageChange = function () { console.log('CONSOLEMSG:', desk.consoleMessage); }
4975
- desk.m.ImageType = webpSupport?4:1; // Send 4 if WebP is supported, otherwise send 1 for JPEG.
4976
- desk.m.CompressionLevel = multidesktopsettings.quality;
4977
- desk.m.ScalingLevel = multidesktopsettings.scaling;
4978
- if (multidesktopsettings.framerate) { desk.m.FrameRateTimer = multidesktopsettings.framerate; }
4979
- if (multidesktopsettings.swapmouse) { desk.m.SwapMouse = multidesktopsettings.swapmouse; }
4980
- if (multidesktopsettings.rmw) { desk.m.ReverseMouseWheel = multidesktopsettings.rmw; }
4981
- if (multidesktopsettings.remotekeymap == true) { desk.m.remoteKeyMap = multidesktopsettings.remotekeymap; }
4982
- //desk.m.onDisplayinfo = deskDisplayInfo;
4983
- desk.m.onScreenSizeChange = mdeskAdjust; // Multi-Desktop Adjust
4984
- //if (debugmode > 0) { desk.m.onScreenSizeChange = mdeskAdjust; }
4985
- desk.Start(nodeid);
4986
- desk.contype = 1;
4987
- multiDesktop[nodeid] = desk;
4988
- }
4989
- } else {
4990
- // Disconnect and clean up the remote desktop
4991
- desk.Stop();
4992
- delete multiDesktop[nodeid];
4993
- }
4994
- }
4995
-
4996
- function getMeshActions(mesh, meshrights) {
4997
- if ((meshrights & 4) == 0) return '';
4998
- var r = '';
4999
- if (mesh.mtype == 1) {
This file is too large to show in full.