Browse code

Changed majority of files.

DoubleBastionAdmin authored on 30/11/2024 06:56:40
Showing 1 changed files
... ...
@@ -1,6 +1,6 @@
1 1
 <?php
2 2
 /**
3
- *  Copyright (C) 2021  Double Bastion LLC
3
+ *  Copyright (C) 2022, 2024  Double Bastion LLC
4 4
  *
5 5
  *  This file is part of Roundpin, which is licensed under the
6 6
  *  GNU Affero General Public License Version 3.0. The license terms
... ...
@@ -18,19 +18,22 @@
18 18
   MIT License. See the LICENSE file at the top of the source tree.
19 19
 */
20 20
 
21
+session_start();
22
+
23
+header('Set-Cookie: PHPSESSID= ' . session_id() . '; SameSite=strict; Secure=true; HttpOnly=true;');
24
+
21 25
 $retrievedstringinit = $_GET['param'];
26
+
22 27
 $retrievedstring = hex2bin($retrievedstringinit);
23 28
 
24 29
 if ($retrievedstring != '') {
25 30
 
26
-    session_start();
27
-
28 31
     define('ACCESSCONST', TRUE);
29 32
 
30
-    require('../db-connect.php');
33
+    require('../src/db-connect.php');
31 34
 
32 35
     // Extract the secret from the configuration file
33
-    $configfilestring = file_get_contents('../roundpin-config.php'); 
36
+    $configfilestring = file_get_contents('../src/roundpin-config.php');
34 37
 
35 38
     if (preg_match_all('[include|include_once|require|require_once]', $configfilestring) != 0) {
36 39
 
... ...
@@ -57,7 +60,7 @@ if ($retrievedstring != '') {
57 60
 
58 61
     } else {
59 62
 
60
-        $configfilelines = file('../roundpin-config.php');
63
+        $configfilelines = file('../src/roundpin-config.php');
61 64
 
62 65
         if (count($configfilelines) != 0) {
63 66
            foreach ($configfilelines as $keyfile => $valuefile) {
... ...
@@ -80,21 +83,38 @@ if ($retrievedstring != '') {
80 83
     $userExtDecComp = explode("|", $userExtDec);
81 84
     $userName = $userExtDecComp[0];
82 85
     $extForExtern = $userExtDecComp[1];
86
+    $retrievedVideoConfExt = $userExtDecComp[2];
87
+    $rtrvdVidConferenceTag = $userExtDecComp[3];
88
+    $retrievedWebSocketPath = $userExtDecComp[4];
83 89
 
84 90
     $retrievedSipUsername = $extForExtern;
85 91
 
86
-    // Get the relevant information for the superadmin who created the external access link
87
-    $query1 = $mysqli->query("SELECT id, userrole, username, wss_server, stun_server, video_conf_extension, enabled FROM app_users WHERE userrole = 'superadmin' AND BINARY username = '$userName' AND enabled = 1");
88
-    $queryres = $query1->fetch_array();
92
+    // Get the relevant information for the user who created the external access link
93
+    $query0 = $mysqli->query("SELECT id, userrole, username, wss_server, stun_server, enabled FROM app_users WHERE (userrole = 'admin' OR userrole = 'superadmin') AND BINARY username = '$userName' AND enabled = 1");
94
+    $queryres = $query0->fetch_array();
89 95
     $userID = $queryres[0];
90 96
     $retrievedWssServer = $queryres[3];
91 97
     $retrievedStunServer = $queryres[4];
92
-    $retrievedVideoConfExt = $queryres[5];
98
+
99
+    $enabled = 1;
100
+    $query1 = $mysqli->prepare("SELECT id, userrole, username, enabled FROM app_users WHERE (userrole = 'admin' OR userrole = 'superadmin') 
101
+                                AND BINARY username = ? AND enabled = ?");
102
+    $query1->bind_param("si", $userName, $enabled);
103
+    $query1->execute();
104
+    $query1res = $query1->get_result()->fetch_assoc();
105
+
106
+    if (!$query1res) { exit(); }
93 107
 
94 108
     // Get the SIP password from the 'external_users' table
95
-    $query2 = $mysqli->query("SELECT id, userid, exten_for_external, exten_for_ext_pass FROM external_users WHERE userid = '$userID' AND exten_for_external = '$extForExtern'");
96
-    $extqueryres = $query2->fetch_array();
97
-    $extensionPass = $extqueryres[3];
109
+    $query2 = $mysqli->prepare("SELECT id, userid, exten_for_external, exten_for_ext_pass FROM external_users WHERE userid = ? AND exten_for_external = ? AND conf_extension = ?");
110
+    $query2->bind_param("iss", $userID, $extForExtern, $retrievedVideoConfExt);
111
+    $query2->execute();
112
+//    $extqueryres = $query2->get_result()->fetch_array();
113
+    $extqueryres = $query2->get_result()->fetch_assoc();
114
+
115
+    if (!$extqueryres) { exit(); }
116
+
117
+    $extensionPass = $extqueryres['exten_for_ext_pass'];
98 118
 
99 119
     // Decrypt the SIP password
100 120
     $componentpkey = explode(':', $extensionPass);
... ...
@@ -113,382 +133,1013 @@ if ($retrievedstring != '') {
113 133
 <head>
114 134
     <meta charset="utf-8" />
115 135
     <title>Roundpin Video Conference</title>
116
-    <link rel="stylesheet" type="text/css" href="css/conference-phone.min.css">
117
-
136
+    <link rel="stylesheet" type="text/css" href="css/conference-phone.css">
118 137
     <link rel="stylesheet" type="text/css" href="../fonts/font-awesome-4.7.0/css/font-awesome.min.css"/>
119
-
120 138
     <link rel="stylesheet" type="text/css" href="../css/jeegoo-1.0.0.min.css"/>
121 139
 
122 140
     <link rel="shortcut icon" type="image/svg" href="../images/favicon.svg" />
141
+
123 142
     <script type="text/javascript" src="js/sdp-interop-sl-1.4.0.min.js"></script>
124
-    <script type="text/javascript" src="js/jssip-3.7.0.min.js"></script>
143
+    <script type="text/javascript" src="js/jssip-3.9.1.min.js"></script>
125 144
     <script type="text/javascript" src="js/utils.min.js"></script>
126 145
     <script type="text/javascript" src="../js/jquery-3.3.1.min.js"></script>
127
-
128
-    <script type="text/javascript" src="js/conference-phone.min.js"></script>
129
-
146
+    <script type="text/javascript" src="js/conference-phone-external.js"></script>
147
+    <script type="text/javascript" src="../js/moment-with-locales-2.24.0.min.js"></script>
130 148
     <script type="text/javascript" src="../js/jquery.jeegoopopup.1.0.0.min.js"></script>
149
+    <script type="text/javascript" src="../js/fix-webm-duration.js"></script>
150
+    <script type="text/javascript" src="../js/crypto-js-4.1.1.min.js"></script>
151
+    <script type="text/javascript" src="../js/jsencrypt.min.js"></script>
131 152
 
132 153
 <script type="text/javascript">
133 154
 
134
-let phone;
135
-let numPressed = null;
155
+//JsSIP.debug.enable('*');
136 156
 
137 157
 let sip_username = "<?php print_r($retrievedSipUsername); ?>";
138 158
 let sip_password = "<?php print_r($retrievedSipPassword); ?>";
139 159
 let wss_server = "<?php print_r($retrievedWssServer); ?>";
160
+let websocketpath = "<?php print_r($retrievedWebSocketPath); ?>";
140 161
 let stun_server = "<?php print_r($retrievedStunServer); ?>";
141 162
 let videoConfExtension = "<?php print_r($retrievedVideoConfExt); ?>";
163
+let videoConfTag = "<?php print_r($rtrvdVidConferenceTag); ?>";
164
+let encExtenPass = "<?php print_r($extensionPass); ?>";
165
+let encExtenPassEnc = encodeURIComponent(encExtenPass);
166
+let showConfUNames = 0;
167
+let profileName = '';
168
+let userRole = 'regular_user';
169
+let userNameDisplay = 0;
170
+let userDescription = '';
171
+
172
+// Check if window is visible to hide notifications, if needed
173
+document.addEventListener('visibilitychange', function() { if (document.hidden) { vcDocIsVisible = false; } else { vcDocIsVisible = true; }});
142 174
 
143 175
 window.onload = function() {
144 176
 
145
-        var mvcount = 0;
146
-	document.getElementById("connect").value = "Connect";
147
-	document.getElementById("connect").disabled = false;
148
-	document.getElementById("call").value = "Call";
149
-	document.getElementById("call").disabled = true;
150
-        document.getElementById("call").style.display = 'none';
151
-        document.getElementById("fullscreen").style.display = 'none';
177
+ var remoteCheck = 0;
178
+ var sipPassDec = '';
179
+
180
+ // Check if the current external participant is banned from the current video conference
181
+ $.ajax({
182
+   type: "POST",
183
+   url: "../src/get-external-user-video-conf-restrictions.php",
184
+   dataType: "JSON",
185
+   data: {
186
+          crvconfextension: videoConfExtension,
187
+          crsipusername: sip_username,
188
+          encextenpass: encExtenPass
189
+   },
190
+   success: function(response) {
191
+
192
+     if (response.notbanned == 'success') {
193
+
194
+
195
+        $.jeegoopopup.close();
196
+
197
+        var html = "<div id=\"enterVConfUName\">";
198
+        html += "<div id=\"extVConfNameDesc\"><img id=\"vConfPrefLogo\" src=\"../images/small-logo.svg\" />";
199
+        html += "<div id=\"vcPopupTitle\"><i class=\"fa fa-video-camera\" aria-hidden=\"true\"></i> Roundpin Video Conference</div>";
200
+        html += "<div id=\"vcPopupText\">Enter the name that the other participants to the conference will see under your video window (you can leave this empty if you prefer):</div></div>";
201
+        html += "<div><input type=\"text\" id=\"extVConfName\"></div>";
202
+        html += "<div id=\"showVCPNchckbx\"><input type=\"checkbox\" id=\"showVCPartNames\"><label id=\"showVCPNmlabel\" for=\"showVCPartNames\">Show participants' names under their video windows.</label></div>";
203
+        html += "</div>";
204
+
205
+        $.jeegoopopup.open({
206
+	        html: html,
207
+	        width: 300,
208
+	        height: 310,
209
+	        center: true,
210
+	        scrolling: 'no',
211
+	        skinClass: 'jg_popup_basic',
212
+	        contentClass: 'enterVConfUser',
213
+	        overlay: true,
214
+	        opacity: 50,
215
+	        draggable: true,
216
+	        resizable: false,
217
+	        fadeIn: 0
218
+        });
152 219
 
153
-	function findMediaView(parent, stream) {
154
-		let nodes = parent.childNodes;
220
+        $("#jg_popup_b").append("<div id=\"saveVConfName\"><button id=\"ConfirmSaveBtn\">Save</button></div>");
155 221
 
156
-		for (let i = 0; i < nodes.length; ++i) {
157
-			if (nodes[i].id == stream.id) {
158
-				return nodes[i];
159
-			}
160
-		}
161
-		return null;
162
-	}
222
+        $("#extVConfName").focus();
163 223
 
164
-        function dtmfMenuShow() {
165
-
166
-                $.jeegoopopup.close();
167
-
168
-	        var leftPos = event.pageX - 90;
169
-	        var topPos = event.pageY + 28;
170
-
171
-		if ($(window).width() < 680) {
172
-		    leftPos = event.pageX - 50;
173
-		}
174
-
175
-	        var html = "<div id=\"sendPinDialPad\">";
176
-	        html += "<div><input type=\"text\" id=\"dialText\" class=\"dialTextInput\"></div>";
177
-	        html += "<table cellspacing=10 cellpadding=0 style=\"margin-left:auto; margin-right: auto\">";
178
-	        html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('1');new Audio('../sounds/dtmf.mp3').play();\"><div>1</div><span>&nbsp;</span></button></td>";
179
-	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('2');new Audio('../sounds/dtmf.mp3').play();\"><div>2</div><span>ABC</span></button></td>";
180
-	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('3');new Audio('../sounds/dtmf.mp3').play();\"><div>3</div><span>DEF</span></button></td></tr>";
181
-	        html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('4');new Audio('../sounds/dtmf.mp3').play();\"><div>4</div><span>GHI</span></button></td>";
182
-	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('5');new Audio('../sounds/dtmf.mp3').play();\"><div>5</div><span>JKL</span></button></td>";
183
-	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('6');new Audio('../sounds/dtmf.mp3').play();\"><div>6</div><span>MNO</span></button></td></tr>";
184
-	        html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('7');new Audio('../sounds/dtmf.mp3').play();\"><div>7</div><span>PQRS</span></button></td>";
185
-	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('8');new Audio('../sounds/dtmf.mp3').play();\"><div>8</div><span>TUV</span></button></td>";
186
-	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('9');new Audio('../sounds/dtmf.mp3').play();\"><div>9</div><span>WXYZ</span></button></td></tr>";
187
-	        html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('*');new Audio('../sounds/dtmf.mp3').play();\">*</button></td>";
188
-	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('0');new Audio('../sounds/dtmf.mp3').play();\">0</button></td>";
189
-	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('#');new Audio('../sounds/dtmf.mp3').play();\">#</button></td></tr>";
190
-	        html += "</table>";
191
-	        html += "</div>";
192
-
193
-	        $.jeegoopopup.open({
194
-			html: html,
195
-			width: "auto",
196
-			height: "auto",
197
-			left: leftPos,
198
-			top: topPos,
199
-			scrolling: 'no',
200
-			skinClass: 'jg_popup_basic',
201
-			overlay: true,
202
-			opacity: 0,
203
-			draggable: true,
204
-			resizable: false,
205
-			fadeIn: 0
206
-	        });
207
-
208
-	        $("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
209
-	        $(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
210
-        }
224
+        $("#ConfirmSaveBtn").click(function () {
225
+
226
+                var showUserNames = ($("#showVCPartNames").is(':checked')) ? "1" : "0";
227
+                showConfUNames = parseInt(showUserNames);
211 228
 
212
-	function createMediaControls(video) {
229
+                var eVConfDisplayName = $("#extVConfName").val();
213 230
 
214
-		let controls = document.createElement("div");
215
-		controls.className = "media-controls";
231
+                if (/^[a-zA-Z0-9\_\-\'\s]*$/.test(eVConfDisplayName)) {
216 232
 
217
-                if (video.srcObject.local == true) {
218
-		        let sendPin = document.createElement("button");
219
-                        sendPin.className = "mediaControlBtn";
220
-                        sendPin.id = "sendPinBtn";
221
-		        sendPin.innerHTML = '<i class="fa fa-keyboard-o" aria-hidden="true" title="Show Keypad"></i>';
222
-                        sendPin.onclick = function() { dtmfMenuShow(); }
233
+                    profileName = eVConfDisplayName;
223 234
 
224
-		        controls.appendChild(sendPin);
235
+                    if (profileName != '') { userNameDisplay = 1; } else { userNameDisplay = 0; }
236
+
237
+                } else {
238
+
239
+                    profileName = '';
240
+                    alert("The name that you entered is not valid. Valid characters are a-z, A-Z, 0-9, _, -, ', empty space and the empty string (no characters).");
225 241
                 }
226 242
 
227
-		let audioTracks = video.srcObject.getAudioTracks();
228
-		if (audioTracks.length > 0) {
229
-                        let muteAudio = document.createElement("button");
230
-                        muteAudio.className = "mediaControlBtn";
231
-                        muteAudio.innerHTML = '<i class="fa fa-microphone-slash" aria-hidden="true" title="Mute Audio"></i>';
232
-			muteAudio.setAttribute("state", "Unmute");
233
-			muteAudio.onclick = function() {
234
-				let state = this.getAttribute("state");
235
-                                if (state == "Mute") {
236
-                                    this.setAttribute("state", "Unmute");
237
-                                    this.innerHTML = '<i class="fa fa-microphone-slash" aria-hidden="true" title="Mute Audio"></i>';
238
-                                } else if (state == "Unmute") {
239
-                                    this.setAttribute("state", "Mute");
240
-                                    this.innerHTML = '<i class="fa fa-microphone" aria-hidden="true" title="Unmute Audio"></i>';
241
-                                }
242
-
243
-				mute(video.srcObject, {audio: this.getAttribute("state") == "Mute"});
244
-			};
245
-			controls.appendChild(muteAudio);
246
-		}
247
-
248
-		let videoTracks = video.srcObject.getVideoTracks();
249
-		if (videoTracks.length > 0) {
250
-                        let muteVideo = document.createElement("button");
251
-                        muteVideo.className = "mediaControlBtn";
252
-                        muteVideo.innerHTML = '<i class="fa fa-ban" aria-hidden="true" title="Mute Video"></i>';
253
-			muteVideo.setAttribute("state", "Unmute");
254
-			muteVideo.onclick = function() {
255
-				let state = this.getAttribute("state");
256
-                                if (state == "Mute") {
257
-                                    this.setAttribute("state", "Unmute");
258
-                                    this.innerHTML = '<i class="fa fa-ban" aria-hidden="true" title="Mute Video"></i>';
259
-                                } else if (state == "Unmute") {
260
-                                    this.setAttribute("state", "Mute");
261
-                                    this.innerHTML = '<i class="fa fa-video-camera" aria-hidden="true" title="Unmute Video"></i>';
262
-                                }
263
-
264
-				mute(video.srcObject, {video: this.getAttribute("state") == "Mute"});
265
-			};
266
-			controls.appendChild(muteVideo);
267
-
268
-                        if (video.srcObject.local == true) {
269
-                                let ScreenShare = document.createElement("button");
270
-                                ScreenShare.className = "mediaControlBtn";
271
-                                ScreenShare.innerHTML = '<i class="fa fa-desktop" aria-hidden="true" title="Share Screen"></i>';
272
-				ScreenShare.onclick = function() {
273
-					phone.ShareScreen();
274
-				};
243
+                if (profileName == '') { return false; }
244
+
245
+		$.ajax({
246
+		    type: "POST",
247
+		    url: "../src/save-external-user-preferences.php",
248
+		    dataType: "JSON",
249
+		    data: {
250
+			    vconfextension: sip_username,
251
+			    encextenpass: encExtenPass,
252
+                            conferenceext: videoConfExtension,
253
+                            evconfdisplayname: profileName,
254
+                            showusernames: showConfUNames
255
+		    },
256
+		    success: function(response) {
257
+
258
+			// Generate a new text chat key pair for the current video conference participant
259
+			var cryptousr = new JSEncrypt({default_key_size: 1024});
260
+			cryptousr.getKey();
261
+			var crVConfUserPubKey = cryptousr.getPublicKey();
262
+			crVConfUserPrivKey = cryptousr.getPrivateKey();
263
+
264
+			$.ajax({
265
+			     type: "POST",
266
+			     url: "../src/save-text-chat-pub-key-ext.php",
267
+			     dataType: "JSON",
268
+			     data: {
269
+				     currentextension: sip_username,
270
+				     currentchatpubkey: crVConfUserPubKey,
271
+			             vconfextension: sip_username,
272
+			             encextenpass: encExtenPass,
273
+                                     conferenceext: videoConfExtension
274
+			     },
275
+			     success: function() {
276
+			     },
277
+			     error: function() {
278
+					alert("An error occurred while attempting to save the new text chat public key!");
279
+			     }
280
+			});
281
+
282
+                        // Generate a RSA key pair for the video conference extension if it hasn't been already generated by a participant who entered the conference earlier
283
+			var crypto = new JSEncrypt({default_key_size: 1024});
284
+			crypto.getKey();
285
+			var crVConfChatPubKey = crypto.getPublicKey();
286
+			var crVConfChatPrivKey = crypto.getPrivateKey();
287
+
288
+			$.ajax({
289
+			     type: "POST",
290
+			     url: "../src/save-text-chat-vconf-keys-ext.php",
291
+			     dataType: "JSON",
292
+			     data: {
293
+				     currentvconfext: videoConfExtension,
294
+				     currentvconfpubkey: crVConfChatPubKey,
295
+				     currentvconfprivkey: crVConfChatPrivKey,
296
+			             vconfextension: sip_username,
297
+			             encextenpass: encExtenPass
298
+			     },
299
+			     success: function() {
300
+			     },
301
+			     error: function() {
302
+					alert("An error occurred while trying to save the new text chat public key!");
303
+			     }
304
+			});
305
+
306
+			// Remove the files received during text chat, from the 'uploads' directory of the current user
307
+			$.ajax({
308
+			     type: "POST",
309
+			     url: "../src/remove-text-chat-uploaded-files-vconf-external.php",
310
+			     dataType: "JSON",
311
+			     data: {
312
+				     vidconfextension: videoConfExtension,
313
+			             vconfextension: sip_username,
314
+			             encextenpass: encExtenPass
315
+			     },
316
+			     success: function(resresult) {
317
+				          if (resresult.note != 'success') {
318
+				              alert("An error occurred while trying to empty the 'uploads' directory!");
319
+				          }
320
+			     },
321
+			     error: function(resresult) {
322
+				              alert("An error occurred while attempting to empty the 'uploads' directory!");
323
+			     }
324
+			});
325
+
326
+                        // Show dialpad
327
+			function dtmfMenuShow() {
328
+
329
+				$.jeegoopopup.close();
330
+
331
+				var leftPos = event.pageX - 90;
332
+				var topPos = event.pageY + 28;
333
+
334
+				if ($(window).width() < 680) {
335
+				    leftPos = event.pageX - 50;
336
+				}
275 337
 
276
-				controls.appendChild(ScreenShare);
338
+				var html = "<div id=\"sendPinDialPad\">";
339
+				html += "<div><input type=\"text\" id=\"dialText\" class=\"dialTextInput\"></div>";
340
+				html += "<table cellspacing=10 cellpadding=0 style=\"margin-left:auto; margin-right: auto\">";
341
+				html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('1');new Audio('../sounds/dtmf.ogg').play();\"><div>1</div><span>&nbsp;</span></button></td>";
342
+				html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('2');new Audio('../sounds/dtmf.ogg').play();\"><div>2</div><span>ABC</span></button></td>";
343
+				html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('3');new Audio('../sounds/dtmf.ogg').play();\"><div>3</div><span>DEF</span></button></td></tr>";
344
+				html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('4');new Audio('../sounds/dtmf.ogg').play();\"><div>4</div><span>GHI</span></button></td>";
345
+				html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('5');new Audio('../sounds/dtmf.ogg').play();\"><div>5</div><span>JKL</span></button></td>";
346
+				html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('6');new Audio('../sounds/dtmf.ogg').play();\"><div>6</div><span>MNO</span></button></td></tr>";
347
+				html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('7');new Audio('../sounds/dtmf.ogg').play();\"><div>7</div><span>PQRS</span></button></td>";
348
+				html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('8');new Audio('../sounds/dtmf.ogg').play();\"><div>8</div><span>TUV</span></button></td>";
349
+				html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('9');new Audio('../sounds/dtmf.ogg').play();\"><div>9</div><span>WXYZ</span></button></td></tr>";
350
+				html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('*');new Audio('../sounds/dtmf.ogg').play();\">*</button></td>";
351
+				html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('0');new Audio('../sounds/dtmf.ogg').play();\">0</button></td>";
352
+				html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('#');new Audio('../sounds/dtmf.ogg').play();\">#</button></td></tr>";
353
+				html += "</table>";
354
+				html += "</div>";
355
+
356
+				$.jeegoopopup.open({
357
+					html: html,
358
+					width: 165,
359
+					height: 270,
360
+					left: leftPos,
361
+					top: topPos,
362
+					scrolling: 'no',
363
+					skinClass: 'jg_popup_basic',
364
+					overlay: true,
365
+					opacity: 0,
366
+					draggable: true,
367
+					resizable: false,
368
+					fadeIn: 0
369
+				});
370
+
371
+				$(window).resize(function() {
372
+				        $.jeegoopopup.width(175).height(280);
373
+				        $.jeegoopopup.center();
374
+				});
375
+
376
+				$("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
377
+				$(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
378
+			}
277 379
 
278
-                                let VideoShare = document.createElement("button");
279
-                                VideoShare.className = "mediaControlBtn";
280
-                                VideoShare.innerHTML = '<i class="fa fa-video-camera" aria-hidden="true" title="Share Camera"></i>';
281
-				VideoShare.onclick = function() {
282
-					phone.ShareVideo();
380
+
381
+                        // Create media control buttons
382
+			function createMediaControls(video, strid) {
383
+
384
+				let controls = document.createElement("div");
385
+				controls.className = "media-controls";
386
+
387
+                                // Hangup
388
+				if (video.srcObject.local == true) {
389
+					let hangupBtn = document.createElement("button");
390
+				        hangupBtn.className = "mediaControlBtn";
391
+				        hangupBtn.id = "hangupConf";
392
+					hangupBtn.innerHTML = '<i class="fa fa-power-off" aria-hidden="true" title="Hangup"></i>';
393
+				        hangupBtn.onclick = function() {
394
+				                               if (confirm("Do you really want to leave the conference ?")) {
395
+                                                                   try { phone.disconnect(); } catch(e) { return; }
396
+				                                   window.close();
397
+                                                                   document.getElementsByTagName("body")[0].innerHTML = '<h4 style="text-align:center;color:#595959;">You have closed the video conference call !</h4>';
398
+				                               }
399
+				        }
400
+
401
+					controls.appendChild(hangupBtn);
402
+				}
403
+
404
+                                // Open keypad
405
+				if (video.srcObject.local == true) {
406
+					let sendPin = document.createElement("button");
407
+				        sendPin.className = "mediaControlBtn";
408
+				        sendPin.id = "sendPinBtn";
409
+					sendPin.innerHTML = '<i class="fa fa-keyboard-o" aria-hidden="true" title="Show Keypad"></i>';
410
+				        sendPin.onclick = function() { dtmfMenuShow(); }
411
+
412
+					controls.appendChild(sendPin);
413
+				}
414
+
415
+
416
+				// Public conference messaging
417
+				if (video.srcObject.local == true) {
418
+
419
+					let textChat = document.createElement("button");
420
+				        textChat.className = "mediaControlBtn";
421
+				        textChat.id = "textChatBtn";
422
+					textChat.innerHTML = '<i class="fa fa-commenting-o" aria-hidden="true" title="Send Public Message..."></i>';
423
+				        textChat.onclick = function() {
424
+
425
+				                if (messageWindowState != 'closed') { alert("The public messaging window is already open!"); return; }
426
+
427
+						var chathtml = "<div id=\"publicTextMessages\">";
428
+				                chathtml += "<div id=\"windowCtrls\"><img id=\"closeImg\" src=\"../images/3_close.svg\" title=\"Close\"><img id=\"maximizeImg\" src=\"../images/2_maximize.svg\" title=\"Maximize\"><img id=\"restoreImg\" src=\"../images/4_restore.svg\" title=\"Restore\"><img id=\"minimizeImg\" src=\"../images/1_minimize.svg\" title=\"Minimize\"><img id=\"publicMessageImg\" src=\"../images/PublicMessage.svg\" title=\"Public Message\"></div>";
429
+				                chathtml += "<div id=\"dragPubMessageWindow\" style=\"display:block;position:absolute;width:100%;height:10px;top:4px;text-align:center;z-index:20;\"><i id=\"dragPublicMWindow\" class=\"fa fa-ellipsis-h\" aria-hidden=\"true\" title=\"Drag Button\" style=\"display:block;position:relative;margin: 0px auto;color:#d0d0d0;font-size:17px;cursor:grab;\"></i></div>";
430
+				                chathtml += "<div id='pubMTopBar' style='display:block;margin: 8px auto;text-align:center;padding-bottom: 6px;'><img src='../images/small-logo.svg' style='display:block;position:relative;margin: 7px auto 0px auto;padding-left:80px;user-select: none;pointer-events: none;' draggable='false'><span style='display:inline-block;margin: -6px 0px 0px 0px;font-weight:600;color:#224573;user-select: none;'>Public Text Messaging - Room: <span style='color:#379b77'>"+ videoConfTag +"</span> ("+ videoConfExtension +")</span></div>";
431
+						chathtml += "<div id=\"receiveTextMessage\"><div id='downloadVConfHst' title='Download Text Conversation'><i class='fa fa-download'></i></div></div>";
432
+				                chathtml += "<div id=\"emojiMenu\" style=\"display:none\"></div>";
433
+				                chathtml += "<div id=\"sendTMessage\"><table cellspacing=\"0\" cellpadding=\"0\" id=\"sendMessageTbl\"><tr><td style=\"height: 100%;width: 100%;\"><textarea id=\"sendTextMessage\" class=\"chatMessage\" placeholder=\"Type the message here, then click the paper plane button or press Ctrl + Enter to send it.\"></textarea></td>";
434
+				                chathtml += "<td style=\"display:block;width:36px;margin:0px;\"><button id=\"sendTextChatBtn\" class=\"roundButtonsSpec\" title=\"Send Message\"><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i></button>";
435
+				                chathtml += "<button id=\"selectEmoticon\" class=\"roundButtonsSpec\" title=\"Select Emoticon\"><i class=\"fa fa-smile-o\"></i></button>";
436
+				                chathtml += "<button id=\"sendFileVC\" class=\"roundButtonsSpec\" title=\"Send File\"><i class=\"fa fa-file-text-o\"></i></button></td></tr></table></div>";
437
+						chathtml += "</div>";
438
+
439
+				                $("#media-views").append(chathtml);
440
+				                $("#publicTextMessages").css("display", "block");
441
+
442
+				                $("#restoreImg").hide();
443
+						$("#sendTextMessage").focus();
444
+				                messageWindowState = 'restored';
445
+
446
+				                // Bring window forward when clicking on it
447
+				                $("#publicTextMessages").click(function (e) {
448
+				                   if (!$(e.target).hasClass('recMessageBtn')) {
449
+				                       $("#publicTextMessages").css("z-index", 21);
450
+				                   }
451
+				                });
452
+
453
+				                // Make the window draggable
454
+						function makePubWndDraggable(e){
455
+
456
+						       window.pmdragging = {};
457
+						       pmdragging.pageX0 = e.pageX;
458
+						       pmdragging.pageY0 = e.pageY;
459
+				                       pmdragging.elem = $("#publicTextMessages");
460
+				                       pmdragging.offset0 = $("#publicTextMessages").offset();
461
+
462
+						       function handle_dragging(e){
463
+							   var left = pmdragging.offset0.left + (e.pageX - pmdragging.pageX0);
464
+							   var top = pmdragging.offset0.top + (e.pageY - pmdragging.pageY0);
465
+							   $(pmdragging.elem).offset({top: top, left: left});
466
+						       }
467
+
468
+						       function handle_mouseup(e){
469
+							   $('body').off('mousemove', handle_dragging).off('mouseup', handle_mouseup);
470
+						       }
471
+
472
+						       $('body').on('mouseup', handle_mouseup).on('mousemove', handle_dragging);
473
+						}
474
+
475
+				                $("#dragPubMessageWindow").mousedown(makePubWndDraggable);
476
+
477
+
478
+				                // Open private message window when clicking on username in received message
479
+				                $("#receiveTextMessage").on("click", ".recMessageBtn", function() {
480
+
481
+                                                   var messageDestPre = $(this).text();
482
+                                                   var messageDest = messageDestPre.slice(0, -2);
483
+				                   var crntExtenfirst = messageDest.split("(");
484
+				                   var crntExtensec = crntExtenfirst[1].split(")");
485
+				                   var crntTgtExten = crntExtensec[0];
486
+				                   if (messageWindowStatePM[crntTgtExten] == 'minimized' || messageWindowStatePM[crntTgtExten] == 'restored') {
487
+				                       alert("The private messaging window for this conference participant is already open!");
488
+				                   } else {
489
+				                       phone.openPrivateMessageWindow(messageDest, crntTgtExten);
490
+				                   }
491
+				                });
492
+
493
+				                // Select emoticon
494
+				                $("#selectEmoticon").click(function() {
495
+
496
+						    var messageContainer = $("#emojiMenu");
497
+						    var textarea = $("#sendTextMessage");
498
+
499
+						    if (messageContainer.is(":visible")) { messageContainer.hide(); } else { messageContainer.show(); }
500
+
501
+						    var menuBar = $("<div>");
502
+						    menuBar.prop("class", "emojiButton");
503
+						    var emojis = ["😀","😁","😂","😃","😄","😅","😆","😊","😦","😉","😊","😋","😌","😍","😎","😏","😐","😑","😒","😓","😔","😕","😖","😗","😘","😙","😚","😛","😜","😝","😞","😟","😠","😡","😢","😣","😤","😥","😦","😧","😨","😩","😪","😫","😬","😭","😮","😯","😰","😱","😲","😳","😴","😵","😶","😷","🙁","🙂","🙃","🙄","🤐","🤑","🤒","🤓","🤔","🤕","🤠","🤡","🤢","🤣","🤤","🤥","🤧","🤨","🤩","🤪","🤫","🤬","🤭","🤯","🤗","🧐"];
504
+						    $.each(emojis, function(i,e){
505
+							       var emoji = $("<button>");
506
+							       emoji.html(e);
507
+							       emoji.on('click', function() {
508
+								    var i = textarea.prop('selectionStart');
509
+								    var v = textarea.val();
510
+								    textarea.val(v.substring(0, i) + " " + $(this).html() + v.substring(i, v.length) + " ");
511
+
512
+								    messageContainer.hide();
513
+								    textarea.focus();
514
+							       });
515
+							       menuBar.append(emoji);
516
+						    });
517
+
518
+						    $("#sendTextMessage,#receiveTextMessage").on('click', function(){
519
+						       messageContainer.hide();
520
+						    });
521
+
522
+						    messageContainer.empty();
523
+						    messageContainer.append(menuBar);
524
+				                });
525
+
526
+						// Show the 'Download Text Conversation' button
527
+						$("#receiveTextMessage").mouseenter(function() {
528
+						   $("#downloadVConfHst").css("display", "block");
529
+						});
530
+						$("#receiveTextMessage").mouseleave(function() {
531
+						   $("#downloadVConfHst").css("display", "none");
532
+						});
533
+
534
+						// Download chat history
535
+						$("#downloadVConfHst").click(function() { phone.DownloadChatHistoryVC(videoConfExtension, videoConfTag); });
536
+
537
+				                // Send message to video conference participants
538
+				                function SendPubChatMessage() {
539
+
540
+				                        let textToSendRaw = $("#sendTextMessage").val().trim();
541
+				                        let textToSend = phone.ReformatVCMessage(textToSendRaw);
542
+				                        let targetUser = '';
543
+
544
+							// When a file is sent
545
+							if (sendFileCheckVC == 1) {
546
+
547
+//				                             $("#receiveTextMessage").after("<span id='sendFileLoaderVC'></span>");
548
+                                                             $("#receiveTextMessage").append("<span id='sendFileLoaderVC'></span>");
549
+				                             sendFileChatErrVC = '';
550
+
551
+				                             $("#sendFileFormChatVC").on('submit', function(ev) {
552
+
553
+								   ev.preventDefault();
554
+
555
+								   $.ajax({
556
+									type: 'POST',
557
+									url: '../src/text-chat-vconf-upload-file-ext.php',
558
+									data: new FormData(this),
559
+									dataType: "JSON",
560
+									contentType: false,
561
+									cache: false,
562
+									processData:false,
563
+									success: function(respdata) { 
564
+
565
+                                                                                    var mserrorcheck = false;
566
+
567
+										    if (respdata.error != '') {
568
+
569
+				                                                        sendFileChatErrVC = respdata.error;
570
+											$("#sendFileFormChatVC").remove();
571
+											$("#sendFileLoaderVC").remove();
572
+                                                                                        sendFileCheckVC = 0;
573
+											alert("Error: " + respdata.error);
574
+
575
+										    } else {
576
+
577
+				                                                        // Send the text message
578
+											phone.sendConfMessage(textToSendRaw, { From: profileName + " (" + sip_username + "): ", To: targetUser, handlers: {
579
+											   onSuccessResponse(response) {
580
+											       console.log("Message Sent: " + response);
581
+											   },
582
+											   onErrorResponse(response) {
583
+                                                                                               mserrorcheck = true;
584
+											       console.log("Message ERROR: " + response);
585
+                                                                                               alert("The message couldn't be sent. Message ERROR: " + response);
586
+											   },
587
+											   onTransportError() {
588
+											       console.log("Could not send message");
589
+											   },
590
+											   onRequestTimeout() {
591
+											       console.log("Timeout sending message");
592
+											   },
593
+											   onDialogError() {
594
+											      console.log("Dialog Error sending message");
595
+											   },
596
+											}});
597
+
598
+                                                                                        if (mserrorcheck == false) {
599
+
600
+											    $("#sendTextMessage").val("");
601
+											    let currentTime = new Date().toLocaleTimeString();
602
+
603
+				                                                            // Append the sent message
604
+											    if (textToSend != '') {
605
+											        $("#receiveTextMessage").append("<div class='textMessageSent textMsgVConf'><span class='sentMessageBtn'>"+ profileName +" ("+ sip_username +"):</span><div class='srMsgVConfcont'>"+ textToSend +"</div><div class='messageDate'>"+ currentTime +"<i class='fa fa-check sentMsTick'></i></div></div>"); 
606
+											    }
607
+
608
+				                                                            // Append the 'Download file' section
609
+											    let currentflTime = new Date().toLocaleTimeString();
610
+
611
+											    $("#receiveTextMessage").append("<div class='textMessageSent textMsgVConf'><span class='sentMessageBtn'>"+ profileName +" ("+ sip_username +"):</span><div class='srMsgVConfcont'>Download file: <a href='../src/download-sent-chat-file-ext.php?sipusername="+ sip_username +"&encextenpass="+ encExtenPassEnc +"&destSipUser="+ videoConfExtension +"&sentFlNm="+ upFileNameVC +"' target='_blank'>"+ upFileNameVC +"</a></div><div class='messageDate'>"+ currentflTime +"</div></div>");
612
+                                                                                        }
613
+
614
+										        $("#sendFileFormChatVC").remove();
615
+									                $("#sendFileLoaderVC").remove();
616
+				                                                    }
617
+
618
+									},
619
+									error: function(respdata) {
620
+										    $("#sendFileFormChatVC").remove();
621
+										    $("#sendFileLoaderVC").remove();
622
+										    alert("An error occurred while sending the file!");
623
+									}     
624
+								   });
625
+
626
+				                             });
627
+
628
+				                             $("#sendFileFormChatVC").submit();
629
+
630
+							} else {
631
+
632
+                                                               var mserrorcheckwf = false;
633
+
634
+				                               // Send the text message
635
+							       phone.sendConfMessage(textToSendRaw, { From: profileName + " (" + sip_username + "): ", To: targetUser, handlers: {
636
+								  onSuccessResponse(response) {
637
+								      console.log("Message Sent: " + response);
638
+								  },
639
+								  onErrorResponse(response) {
640
+                                                                      mserrorcheckwf = true;
641
+								      console.log("Message ERROR: " + response);
642
+                                                                      alert("The message couldn't be sent. Message ERROR: " + response);
643
+								  },
644
+								  onTransportError() {
645
+								      console.log("Could not send message");
646
+								  },
647
+								  onRequestTimeout() {
648
+								      console.log("Timeout sending message");
649
+								  },
650
+								  onDialogError() {
651
+								      console.log("Dialog Error sending message");
652
+								  },
653
+							       }});
654
+
655
+
656
+                                                               if (mserrorcheckwf == false) {
657
+
658
+				                                   $("#sendTextMessage").val("");
659
+				                                   let currentTime = new Date().toLocaleTimeString();
660
+
661
+				                                   // Append the sent message
662
+				                                   if (textToSend != '') {
663
+				                                       $("#receiveTextMessage").append("<div class='textMessageSent textMsgVConf'><span class='sentMessageBtn'>"+ profileName +" ("+ sip_username +"):</span><div class='srMsgVConfcont'>"+ textToSend +"</div><div class='messageDate'>"+ currentTime +"<i class='fa fa-check sentMsTick'></i></div></div>"); 
664
+				                                   }
665
+                                                               }
666
+
667
+				                        }
668
+				       
669
+				                        $("#receiveTextMessage").scrollTop($("#receiveTextMessage")[0].scrollHeight);
670
+
671
+				                }
672
+
673
+				                // Send the message when clicking on the 'Send Message' button
674
+						$("#sendTextChatBtn").click(function() { SendPubChatMessage(); });
675
+
676
+				                // Send the message when pressing Ctrl + Enter
677
+				                $("#sendTextMessage").keydown(function() {
678
+						    var keycode = (event.keyCode ? event.keyCode : event.which);
679
+						    if (keycode == '13') {
680
+							if (event.ctrlKey) {
681
+							    SendPubChatMessage();
682
+							    return false;
683
+							}
684
+						    }
685
+				                });
686
+
687
+
688
+				                // Select the file to send
689
+				                $("#sendFileVC").click(function() {
690
+
691
+						      $('#selectedFileVC').val('');
692
+						      $("#upFileVC").empty();
693
+
694
+						      var uploadfilevc = '<form id="sendFileFormChatVC" enctype="multipart/form-data">';
695
+						      uploadfilevc += '<input type="hidden" name="MAX_FILE_SIZE" value="786432000" />';
696
+						      uploadfilevc += '<input type="hidden" name="vcextension" value="'+ videoConfExtension +'" />';
697
+						      uploadfilevc += '<input type="hidden" name="sipusername" value="'+ sip_username +'" />';
698
+						      uploadfilevc += '<input type="hidden" name="encextenpass" value="'+ encExtenPass +'" />';
699
+						      uploadfilevc += '<label for="selectedFileVC" class="customBrowseButtonVC">Select File</label>';
700
+						      uploadfilevc += '<span id="upFileVC"></span>';
701
+						      uploadfilevc += '<input type="file" id="selectedFileVC" name="uploadedFileVC" />';
702
+						      uploadfilevc += '<input type="submit" id="submitFileChatVC" value="Send File" style="visibility:hidden;"/>';
703
+						      uploadfilevc += '</form>';
704
+
705
+
706
+						      if ($("#sendFileFormChatVC").is(":visible")) {
707
+							  $("#sendFileFormChatVC").remove();
708
+							  sendFileCheckVC = 0;
709
+						      } else {
710
+		                                          sendFileCheckVC = 1;
711
+							  $("#sendTextMessage").before(uploadfilevc);
712
+							  $("#sendFileFormChatVC").css("display", "block");
713
+
714
+							  $("#selectedFileVC").bind("change", function() {
715
+							     upFileNameVC = $(this).val().split('\\').pop();
716
+							     if (/^[a-zA-Z0-9\-\_\.]+$/.test(upFileNameVC)) {
717
+                                                                 $("#upFileVC").css("display", "inline-block");
718
+								 $("#upFileVC").html(upFileNameVC);
719
+							     } else {
720
+								   $("#sendFileFormChatVC").remove();
721
+								   sendFileCheckVC = 0;
722
+								   alert("The name of the uploaded file is not valid!");
723
+							     }
724
+							  });
725
+						      }
726
+
727
+				                });
728
+
729
+
730
+				                // Position the window
731
+						let maxHeight = parseInt(0.88 * $(window).height());
732
+						let maxWidth = parseInt(maxHeight * 1.24);
733
+				                let wTop = parseInt( ($(window).height() / 2) - 290 );
734
+				                let wLeft = parseInt( ($(window).width() / 2) - 280 );
735
+				                $("#publicMessageImg").hide();
736
+
737
+
738
+						if (maxWidth < 620 || maxHeight < 500) { 
739
+						    $("#publicTextMessages").css({ "width": maxWidth, "height": maxHeight, "top": wTop, "left": wLeft });
740
+						    $("#maximizeImg").hide();
741
+				                    $("#restoreImg").hide();
742
+						} else { 
743
+						    $("#publicTextMessages").css({ "width": 620, "height": 500, "top": wTop, "left": wLeft });
744
+				                    $("#minimizeImg").show();
745
+						    $("#maximizeImg").show();
746
+				                    $("#restoreImg").hide();
747
+						}
748
+
749
+				                // Handle window position when resizing browser window
750
+						$(window).resize(function() {
751
+
752
+						  let maxHeight = parseInt(0.88 * $(window).height());
753
+				                  let maxWidth = parseInt(maxHeight * 1.24);
754
+				                  let wTop = parseInt( ($(window).height() / 2) - 290 );
755
+				                  let wLeft = parseInt( ($(window).width() / 2) - 280 );
756
+				                  $("#receiveTextMessage").show();
757
+				                  $("#sendTMessage").show();
758
+				                  $("#pubMTopBar").show();
759
+				                  $("#publicMessageImg").hide();
760
+
761
+
762
+						  if (maxWidth < 620 || maxHeight < 500) { 
763
+						      $("#publicTextMessages").css({ "width": maxWidth, "height": maxHeight, "top": wTop, "left": wLeft });
764
+						      $("#maximizeImg").hide();
765
+				                      $("#restoreImg").hide();
766
+						  } else { 
767
+						      $("#publicTextMessages").css({ "width": 620, "height": 500, "top": wTop, "left": wLeft });
768
+		       				      $("#minimizeImg").show();
769
+						      $("#maximizeImg").show();
770
+				                      $("#restoreImg").hide();
771
+						  }
772
+
773
+						});
774
+
775
+				                // Handle clicking on window control buttons
776
+						$("#maximizeImg").click(function() { messageWindowState = 'maximized'; $("#publicTextMessages").css({ "width": maxWidth, "height": maxHeight, "top": wTop - 40, "left": wLeft - 40 }); $("#maximizeImg,#publicMessageImg").hide(); $("#minimizeImg,#pubMTopBar,#restoreImg,#receiveTextMessage,#sendTMessage").show(); $("#receiveTextMessage").css("height", "64%"); $("#recPubMessage").remove(); });
777
+						$("#minimizeImg").click(function() { messageWindowState = 'minimized'; $("#publicTextMessages").css({ "display": "block", "position": "fixed", "width": 215, "height": 34, "inset": "auto auto 1px 3px" }); $("#minimizeImg,#pubMTopBar,#receiveTextMessage,#sendTMessage").hide(); $("#maximizeImg,#restoreImg,#publicMessageImg").show(); $("#windowCtrls").css("margin", "10px 10px 0px 0px"); $("#dragPubMessageWindow").css("top", "-1px"); });
778
+				                $("#restoreImg").click(function() { messageWindowState = 'restored'; $("#publicTextMessages").css({ "width": 620, "height": 500, "top": wTop, "left": wLeft }); $("#restoreImg,#publicMessageImg").hide(); $("#maximizeImg,#pubMTopBar,#minimizeImg,#receiveTextMessage,#sendTMessage").show(); $("#receiveTextMessage").css("height", "54%"); $("#dragPubMessageWindow").css("top", "4px"); $("#recPubMessage").remove(); });
779
+						$("#closeImg").click(function() { messageWindowState = 'closed'; $("#publicTextMessages").remove();  $("#recPubMessage").remove(); });
780
+
781
+						$(window).on('keydown', function(event) { if (event.key == "Escape") { messageWindowState = 'closed'; $("#publicTextMessages").remove();  $("#recPubMessage").remove(); } });
782
+
783
+				        }
784
+
785
+					controls.appendChild(textChat);
786
+				}
787
+
788
+				// Private conference messaging
789
+				if (video.srcObject.local == false) {
790
+
791
+					let pmtextChat = document.createElement("button");
792
+				        pmtextChat.className = "mediaControlBtn";
793
+				        pmtextChat.id = "textChatBtnPM";
794
+					pmtextChat.innerHTML = '<i class="fa fa-commenting-o" aria-hidden="true" title="Send private message to this user"></i>';
795
+				        pmtextChat.onclick = function() {
796
+						   let currentMView = document.getElementById("new-media-view"+strid);
797
+						   let crMViewName = currentMView.getAttribute("name");
798
+						   let targetCnfExt = crMViewName.slice(4);
799
+
800
+				                   let currentVidView = document.getElementById("video-view"+strid);
801
+				                   let destName = currentVidView.getAttribute("name") + " ("+ targetCnfExt +")";
802
+
803
+				                   if (messageWindowStatePM[targetCnfExt] == 'minimized' || messageWindowStatePM[targetCnfExt] == 'restored') {
804
+				                       alert("The private message window for this conference participant is already open!");
805
+				                   } else {
806
+				                       phone.openPrivateMessageWindow(destName, targetCnfExt);
807
+				                   }
808
+				        }
809
+					controls.appendChild(pmtextChat);
810
+				}
811
+
812
+
813
+				// Record conference
814
+				if (video.srcObject.local == true) {
815
+					let recordConf = document.createElement("button");
816
+				        recordConf.className = "mediaControlBtn";
817
+				        recordConf.id = "recordConfBtnStart";
818
+					recordConf.innerHTML = '<i class="fa fa-dot-circle-o" aria-hidden="true" title="Record Conference..."></i>';
819
+				        recordConf.onclick = function() { 
820
+								   phone.recordVideoConference();                                           
821
+				        }
822
+
823
+					controls.appendChild(recordConf);
824
+				}
825
+
826
+                                // Mute/Unmute audio
827
+				let audioTracks = video.srcObject.getAudioTracks();
828
+				if (audioTracks.length > 0) {
829
+				        let muteAudio = document.createElement("button");
830
+				        muteAudio.className = "mediaControlBtn";
831
+				        muteAudio.innerHTML = '<i class="fa fa-microphone" aria-hidden="true" title="Mute Audio"></i>';
832
+					muteAudio.setAttribute("state", "Unmute");
833
+					muteAudio.onclick = function() {
834
+						let state = this.getAttribute("state");
835
+				                if (state == "Mute") {
836
+				                    this.setAttribute("state", "Unmute");
837
+				                    this.innerHTML = '<i class="fa fa-microphone" aria-hidden="true" title="Mute Audio"></i>';
838
+				                } else if (state == "Unmute") {
839
+				                    this.setAttribute("state", "Mute");
840
+				                    this.innerHTML = '<i class="fa fa-microphone redmic" aria-hidden="true" title="Unmute Audio"></i>';
841
+				                }
842
+						mute(video.srcObject, {audio: this.getAttribute("state") == "Mute"});
843
+					};
844
+					controls.appendChild(muteAudio);
845
+				}
846
+
847
+				let videoTracks = video.srcObject.getVideoTracks();
848
+				if (videoTracks.length > 0) {
849
+
850
+                                        // Mute/Unmute video
851
+				        let muteVideo = document.createElement("button");
852
+				        muteVideo.className = "mediaControlBtn";
853
+				        muteVideo.innerHTML = '<i class="fa fa-camera" aria-hidden="true" title="Mute Video"></i>';
854
+					muteVideo.setAttribute("state", "Unmute");
855
+					muteVideo.onclick = function() {
856
+						let state = this.getAttribute("state");
857
+				                if (state == "Mute") {
858
+				                    this.setAttribute("state", "Unmute");
859
+				                    this.innerHTML = '<i class="fa fa-camera" aria-hidden="true" title="Mute Video"></i>';
860
+				                } else if (state == "Unmute") {
861
+				                    this.setAttribute("state", "Mute");
862
+				                    this.innerHTML = '<i class="fa fa-camera redcam" aria-hidden="true" title="Unmute Video"></i>';
863
+				                }
864
+
865
+						mute(video.srcObject, {video: this.getAttribute("state") == "Mute"});
866
+					};
867
+					controls.appendChild(muteVideo);
868
+
869
+				        if (video.srcObject.local == true) {
870
+
871
+                                                // Share screen
872
+				                let ScreenShare = document.createElement("button");
873
+				                ScreenShare.className = "mediaControlBtn";
874
+				                ScreenShare.innerHTML = '<i class="fa fa-desktop" aria-hidden="true" title="Share Screen..."></i>';
875
+						ScreenShare.onclick = function() {
876
+							phone.ShareScreen();
877
+						};
878
+
879
+						controls.appendChild(ScreenShare);
880
+
881
+                                                // Reshare camera
882
+				                let VideoShare = document.createElement("button");
883
+				                VideoShare.className = "mediaControlBtn";
884
+				                VideoShare.innerHTML = '<i class="fa fa-video-camera" aria-hidden="true" title="Reshare Camera"></i>';
885
+						VideoShare.onclick = function() {
886
+							phone.ShareVideo();
887
+						};
888
+
889
+						controls.appendChild(VideoShare);
890
+
891
+                                                // View all video windows in full screen
892
+						let allFullScreen = document.createElement("button");
893
+						allFullScreen.className = "mediaControlBtn";
894
+						allFullScreen.id = "fullscreen";
895
+						allFullScreen.innerHTML = '<i class="fa fa-arrows-alt" aria-hidden="true" title="Full Screen"></i>';
896
+						allFullScreen.onclick = function() { toggleFullScreen(document.body); }
897
+
898
+						controls.appendChild(allFullScreen);
899
+
900
+				        }
901
+
902
+                                        // View this video window in full screen
903
+				        let fullScreen = document.createElement("button");
904
+				        fullScreen.className = "mediaControlBtn";
905
+				        fullScreen.innerHTML = '<i class="fa fa-window-maximize" aria-hidden="true" title="Expand Window"></i>';
906
+					fullScreen.onclick = function() {
907
+					    this.fullScreen.request();					
908
+					};
909
+
910
+					fullScreen.fullScreen = new FullScreen(video);
911
+					controls.appendChild(fullScreen);
912
+				}
913
+				return controls;
914
+			}
915
+
916
+
917
+			function createMediaView(stream) {
918
+
919
+				var mediaView = document.createElement("div");
920
+				mediaView.className = "media-view";
921
+				mediaView.id = "new-media-view"+stream.id;
922
+
923
+				let videoView = document.createElement("div");
924
+				videoView.className = "video-view";
925
+				videoView.id = "video-view"+stream.id;
926
+
927
+                                videoView.setAttribute("name", profileName);
928
+
929
+				let video = document.createElement("video");
930
+				video.className = "videoElem";
931
+				video.id = "locVideo"+stream.id;
932
+				video.autoplay = true;
933
+				video.srcObject = stream;
934
+
935
+				video.onloadedmetadata = function() {
936
+
937
+				      let tracks = stream.getVideoTracks();
938
+				      for (let i = 0; i < tracks.length; ++i) {
939
+					   tracks[i].enabled = true;
940
+				      }
283 941
 				};
284 942
 
285
-				controls.appendChild(VideoShare);
286
-                        }
943
+				// Add participant's name at the bottom of the video window
944
+				var userDesc = document.createElement("div");
945
+				userDesc.className = "user-desc";
287 946
 
288
-                        let fullScreen = document.createElement("button");
289
-                        fullScreen.className = "mediaControlBtn";
290
-                        fullScreen.innerHTML = '<i class="fa fa-expand" aria-hidden="true" title="Full Screen"></i>';
291
-			fullScreen.onclick = function() {
292
-			    this.fullScreen.request();					
293
-			};
947
+				// Add the video conference room label at the bottom-right corner of the video window
948
+				var confRoomLabel = document.createElement("div");
949
+				confRoomLabel.className = "vidConfLabel";
950
+				confRoomLabel.innerHTML = "Room: "+ videoConfTag;
294 951
 
295
-			fullScreen.fullScreen = new FullScreen(video);
296
-			controls.appendChild(fullScreen);
297
-		}
298
-		return controls;
299
-	}
952
+				// Add a green border over the video window of the person who is talking
953
+				var talkSignal = document.createElement("div");
954
+				talkSignal.className = "talkDetect";
955
+
956
+				if (stream.local == false) {
957
+
958
+				        let userDescCheck = 0;
959
+
960
+					function checkForVideo() {
961
+
962
+				                mediaView.style.display = 'inline-block';
963
+
964
+				                // Get the profile name/user description from the database
965
+						var StreamID = stream.id;
966
+
967
+						if (userDescCheck < 4 && StreamID != '' && StreamID != 'undefined' && StreamID != null) {
968
+
969
+							let gotChannelId = '';
970
+							for (let i = 0; i < StreamChanTbl.length; i++) {
971
+							     if (StreamChanTbl[i].streamId == StreamID) { gotChannelId = StreamChanTbl[i].channelId; }
972
+							}
973
+
974
+							let gotExtension = '';
975
+							for (let k = 0; k < ExtProNmTbl.length; k++) {
976
+							     if (ExtProNmTbl[k].channelId == gotChannelId) { gotExtension = ExtProNmTbl[k].extension; }
977
+							}
978
+
979
+                                                        if (gotExtension != '') {
980
+
981
+                                                            mediaView.setAttribute("name", "cmv_" + gotExtension);
982
+                                                            talkSignal.id = "talk-detect-" + gotExtension;
983
+
984
+							    $.ajax({
985
+							        type: "POST",
986
+							        url: "../src/get-conf-user-description-ext.php",
987
+							        dataType: "JSON",
988
+							        data: {
989
+								        clrextension: gotExtension,
990
+			                                                vconfextension: sip_username,
991
+			                                                encextenpass: encExtenPass,
992
+                                                                        conferenceext: videoConfExtension
993
+							        },
994
+							        success: function(response) {
995
+								      if (response.result == 'success') { 
996
+						                          userDescription = response.userdescription;
997
+                                                                          videoView.setAttribute("name", userDescription);
998
+
999
+				                                          if (userDescription != 'undefined' && userDescription != null) {
1000
+
1001
+                                                                              userNameDisplay = response.namedisplay;
300 1002
 
301
-	function createMediaView(stream) {
1003
+				                                              if (userNameDisplay == 1 && showConfUNames == 1 && userDescription != '' && userDescription != null) {
1004
+					                                          userDesc.innerHTML = '<span>' + userDescription  + '</span>';
1005
+				                                                  videoView.appendChild(userDesc);
1006
+                                                                                  ++userDescCheck;
1007
+				                                              }
1008
+				                                          }
1009
+                                            
1010
+						                      }
1011
+							        },
1012
+							        error: function(response) {
1013
+								          alert("An error occurred while attempting to retrieve the profile name/user description from the database!");
1014
+							        }
1015
+							    });
302 1016
 
303
-		var mediaView = document.createElement("div");
304
-		mediaView.className = "media-view";
305
-		mediaView.id = "new-media-view"+stream.id;
306
-                mediaView.style.width = localStorage.getItem("VidConfWindowWidth")+"%";
1017
+                                                        }
307 1018
 
308
-		var videoView = document.createElement("div");
309
-                videoView.className = "video-view";
310
-                videoView.id = "video-view"+stream.id;
1019
+						}
311 1020
 
312
-		var video = document.createElement("video");
313
-                video.className = "videoElem";
314
-                video.id = "locVideo"+stream.id;
315
-		video.autoplay = true;
1021
+					}
316 1022
 
317
-		video.srcObject = stream;
318
-		video.onloadedmetadata = function() {
319
-		      let tracks = stream.getVideoTracks();
1023
+				        checkForVideo();
1024
+					setInterval(checkForVideo, 1000);
320 1025
 
321
-		      for (let i = 0; i < tracks.length; ++i) {
322
-			   tracks[i].enabled = true;
323
-		      }
324
-		};
1026
+				        if (remoteCheck == 0) {
1027
+				            // Hide our own remote video track
1028
+				            remoteCheck = 1;
1029
+				            document.getElementById(mediaView.id).style.display = 'none';
325 1030
 
326
-		if (stream.local == false) {
327
-			function checkForVideo() {
328
-				if (video.videoWidth < 10 || video.videoHeight < 10) {
329
-                                    mediaView.style.display = 'none';
330
-				    return;
1031
+				        } 
331 1032
 				}
332
-                                mediaView.style.display = 'inline';
1033
+
1034
+				// Video elements connected to local streams will by default
1035
+				// echo both the video and the audio back to ourselves. Since
1036
+				// we don't want to hear ourselves we mute it, which mutes only
1037
+				// the audio portion.
1038
+				if (stream.local == true) {
1039
+					video.muted = true;
1040
+
1041
+				        if (showConfUNames == 1) {
1042
+				            userDesc.innerHTML = '<span>' + profileName + '</span>';
1043
+				            videoView.appendChild(userDesc);
1044
+				        }
1045
+
1046
+                                        videoView.appendChild(confRoomLabel);
1047
+				        mediaView.id = "new-media-view" + stream.id;
1048
+				        mediaView.setAttribute("name", "cmv_" + sip_username);
1049
+				}
1050
+
1051
+				videoView.appendChild(video);
1052
+				mediaView.appendChild(talkSignal);
1053
+				mediaView.appendChild(videoView);
1054
+				mediaView.appendChild(createMediaControls(video, stream.id));
1055
+
1056
+				return mediaView;
333 1057
 			}
334
-                        checkForVideo();
335
-			setInterval(checkForVideo, 1000);
336
-		}
337
-
338
-		// Video elements connected to local streams will by default
339
-		// echo both the video and the audio back to ourselves. Since
340
-		// we don't want to hear ourselves we mute it, which mutes only
341
-		// the audio portion.
342
-
343
-		if (stream.local == true) {
344
-			video.muted = true;
345
-		} else if (mvcount == 0) {
346
-                        // We hide our own remote video track
347
-                        mvcount = 1;
348
-                        document.getElementById(mediaView.id).style.display = 'none';
349
-                }
350 1058
 
351
-		videoView.appendChild(video);
352
-		mediaView.appendChild(videoView);
353
-		mediaView.appendChild(createMediaControls(video));
1059
+			phone = new ConferencePhone(sip_username, sip_username, sip_password, wss_server, websocketpath, stun_server, true);
354 1060
 
355
-		return mediaView;
356
-	}
1061
+			sip_password = '';
357 1062
 
358
-	function removeMediaView(parent, stream) {
359
-		let node = findMediaView(parent, stream);
360
-		if (node) {
361
-			parent.removeChild(node);
362
-		}
363
-	}
1063
+			phone.handle("registrationFailed", function () {
1064
+				phone.disconnect();
1065
+			});
364 1066
 
365
-	function getValue(id) {
366
-		let obj = document.getElementById(id);
367
-		return obj.value ? obj.value : obj.placeholder;
368
-	}
1067
+			phone.handle("streamAdded", function (stream) {
1068
+
1069
+				try { document.getElementById("media-views").appendChild(createMediaView(stream)); } catch(e) { return; }
1070
+				++userCount;
1071
+				phone.resizeVideo(userCount);
1072
+			});
369 1073
 
370
-        document.getElementById("connect").addEventListener("click", function() {
371
-		if (document.getElementById("connect").value == "Disconnect") {
372
-			document.getElementById("call").value = "Call";
373
-			document.getElementById("call").disabled = true;
374
-			document.getElementById("connect").value = "Disconnecting";
375
-			document.getElementById("connect").disabled = true;
1074
+			phone.connect();
376 1075
 
377
-			phone.disconnect();
378
-			return;
379
-		}
380 1076
 
381
-                phone = new ConferencePhone(sip_username, sip_username, sip_password, wss_server, stun_server, true);
1077
+			let constraints = { audio: true, video: true };
382 1078
 
383
-                sip_password = '';
1079
+			navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
1080
+			    phone.call(videoConfExtension);
1081
+			}).catch(function(err) { alert("Error getting media devices!"); });
384 1082
 
385
-		phone.handle("connected", function () {
1083
+			document.addEventListener("fullscreenchange", onFullScreenChange, false);
1084
+			document.addEventListener("webkitfullscreenchange", onFullScreenChange, false);
1085
+			document.addEventListener("mozfullscreenchange", onFullScreenChange, false);
386 1086
 
387
-			if (document.getElementById("connect").value != "Disconnect") {
388
-				document.getElementById("connect").value = "Registering";
389
-			} else {
390
-				document.getElementById("connect").value = "Disconnect";
391
-				document.getElementById("connect").disabled = false;
392
-				document.getElementById("call").disabled = false;
1087
+			function onFullScreenChange() {
1088
+			   if (document.mozFullScreenElement != null || document.webkitFullscreenElement != null || document.fullscreenElement != null) {
1089
+			       document.getElementById("fullscreen").style = "color: #0d60e1";
1090
+			   } else { 
1091
+			       document.getElementById("fullscreen").style = "color: #000000";
1092
+			   }
393 1093
 			}
394
-		});
395
-
396
-		phone.handle("disconnected", function () {
397
-			document.getElementById("connect").value = "Connect";
398
-			document.getElementById("connect").disabled = false;
399
-			document.getElementById("call").value = "Call";
400
-			document.getElementById("call").disabled = true;
401
-		});
402
-
403
-		phone.handle("registered", function () {
404
-			document.getElementById("connect").value = "Disconnect";
405
-			document.getElementById("connect").disabled = false;
406
-			document.getElementById("call").disabled = false;
407
-		});
408
-
409
-		phone.handle("registrationFailed", function () {
410
-			phone.disconnect();
411
-		});
412
-
413
-		phone.handle("incoming", function (reason) {
414
-			document.getElementById("call").value = "Answer";
415
-		});
416
-
417
-		phone.handle("failed", function (reason) {
418
-			document.getElementById("call").value = "Call";
419
-			document.getElementById("call").disabled = false;
420
-		});
421
-
422
-		phone.handle("ended", function (reason) {
423
-			document.getElementById("call").value = "Call";
424
-			document.getElementById("call").disabled = document.getElementById("connect").value == "Connect";
425
-		});
426
-
427
-		phone.handle("streamAdded", function (stream) {
428
-			document.getElementById("media-views").appendChild(createMediaView(stream));
429
-			document.getElementById("call").value = "Hangup";
430
-			document.getElementById("call").disabled = false;
431
-                        document.getElementById("call").style.display = 'inline';
432
-                        document.getElementById("fullscreen").style.display = 'inline';
433
-                        document.getElementById("fullscreen").innerHTML = '<i class="fa fa-expand" aria-hidden="true"></i><b>&nbsp; Fullscreen';
434
-		});
435
-
436
-		phone.handle("streamRemoved", function (stream) {
437
-			removeMediaView(document.getElementById("media-views"), stream);
438
-		});
439
-
440
-		phone.connect();
441
-
442
-		document.getElementById("connect").disabled = true;
443
-		document.getElementById("connect").value = "Connecting";
444
-	});
445
-
446
-        document.getElementById("connect").click();
447
-
448
-        let constraints = { video: true, audio: true };
449
-        navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
450
-            phone.call(videoConfExtension);
451
-        }).catch(function(err) { });
452
-
453
-        let node = document.getElementById("call");
454
-
455
-        if (node.value == "Answer") {
456
-	    node.disabled = true;
457
-	    node.value = "Hangup";
458
-	}
459 1094
 
460
-        document.getElementById("call").addEventListener("click", function() {
461
-            if (node.value == "Hangup") {
462
-	        phone.terminate();
463
-                document.getElementById("call").remove();
464
-                window.close();
465
-                document.getElementsByTagName("body")[0].innerHTML = '<h4 style="text-align:center;color:#595959;">You have closed the video conference call ! If you want to enter the conference again, just press the button from below:</h4><button class="enterConfExt" onclick="window.location.reload()">Enter Conference Again</button><h4 style="text-align:center;color:#595959;">Otherwise, you can close this browser tab.</h4>';
466
-            }
1095
+
1096
+			// Get the private key of the current video conference extension, since it may have been created previously by another conference participant
1097
+			$.ajax({
1098
+			  type: "POST",
1099
+			  url: "../src/get-text-chat-vconf-priv-key-ext.php",
1100
+			  dataType: "JSON",
1101
+			  data: {
1102
+			     crntvconfext: videoConfExtension,
1103
+			     vconfextension: sip_username,
1104
+			     encextenpass: encExtenPass
1105
+			  },
1106
+			  success: function(result) {
1107
+
1108
+				if (result.resmessage == 'success') {
1109
+				    currentVconfPrivKey = "`" + result.chatprivkey.join("") + "`";
1110
+				} else {
1111
+				      alert('An error occurred while retrieving the private key for text chat!');
1112
+				}
1113
+			  },
1114
+			  error: function(result) {
1115
+				      alert('An error occurred while attempting to retrieve the private key for text chat!');
1116
+			  }
1117
+			});
1118
+
1119
+
1120
+                    },
1121
+                    error: function(response) {
1122
+                               alert("An error occurred while attempting to save the data to the database!");
1123
+                    }
1124
+                });
1125
+
1126
+
1127
+            $.jeegoopopup.close();
1128
+            $("#jg_popup_b").empty();
1129
+            $("#windowCtrls").empty();
467 1130
         });
468 1131
 
469
-	$("#showConnectionBttns").click(function() {
470
-	  if ($("#connection").is(':visible')) {
471
-	      $("#connection").hide();
472
-	      $("#showConnectionBttns").html('<i class="fa fa-caret-down" aria-hidden="true"></i>');
473
-	  } else { 
474
-	      $("#connection").show();
475
-	      $("#showConnectionBttns").html('<i class="fa fa-caret-up" aria-hidden="true"></i>');
476
-	  }
477
-	});
478
-
479
-	document.addEventListener("fullscreenchange", onFullScreenChange, false);
480
-	document.addEventListener("webkitfullscreenchange", onFullScreenChange, false);
481
-	document.addEventListener("mozfullscreenchange", onFullScreenChange, false);
482
-
483
-	function onFullScreenChange() {
484
-	   if (document.mozFullScreenElement != null || document.webkitFullscreenElement != null || document.fullscreenElement != null) {
485
-	       document.getElementById("fullscreen").innerHTML = '<i class="fa fa-compress" aria-hidden="true"></i><b>&nbsp; Exit Fullscreen';
486
-	       document.getElementById("fullscreen").style.width = "148px";
487
-	   } else { 
488
-	       document.getElementById("fullscreen").innerHTML = '<i class="fa fa-expand" aria-hidden="true"></i><b>&nbsp; Fullscreen';
489
-	       document.getElementById("fullscreen").style.width = "117px";
490
-	   }
491
-	}
1132
+        $(window).resize(function() {
1133
+           $.jeegoopopup.width(300).height(310);
1134
+           $.jeegoopopup.center();
1135
+        });
1136
+
1137
+
1138
+     } else { alert("You are still banned from this video conference!"); }                            
1139
+
1140
+   },
1141
+   error: function(response) { alert("Error while trying to get video conference restrictions data!"); }
1142
+ });
492 1143
 
493 1144
 }; // window.onload
494 1145
 
... ...
@@ -505,14 +1156,8 @@ window.onunload = function() {
505 1156
 </script>
506 1157
 </head>
507 1158
 <body>
508
-	<div id="connection">
509
-               <div id="VideoConferenceLogo"><img src="../images/small-logo.svg" /></div>
510
-	       <input type="button" id="connect" class="connect" value="Connect" style="display:none;" />
511
-               <button id="call" class="call"><i class="fa fa-phone" aria-hidden="true"></i><b>&nbsp; Hangup</b></button>
512
-               <button id="fullscreen" class="fullscreen" onclick="toggleFullScreen(document.body)"><i class="fa fa-expand" aria-hidden="true"></i><b>&nbsp; Fullscreen</b></button>
513
-	</div>
514
-        <div id="showConnectionBttns"><i class="fa fa-caret-down" aria-hidden="true"></i></div>
515
-       <div id="media-views" class="media-views"></div>
1159
+  <input type="button" id="connect" class="connect" value="Connect" style="display: none;" />
1160
+  <div id="media-frame"><div id="media-views" class="media-views"></div></div>
516 1161
 
517 1162
 <script type="text/javascript">
518 1163
 
... ...
@@ -568,7 +1213,7 @@ function toggleFullScreen(elem) {
568 1213
 <?php
569 1214
 
570 1215
 } else {
571
-     header("Location: ../roundpin-login.php");
572
-  }
1216
+     header("Location: ../login.php");
1217
+}
573 1218
 
574 1219
 ?>
Browse code

Created repository.

DoubleBastionAdmin authored on 26/01/2022 20:32:42
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,574 @@
1
+<?php
2
+/**
3
+ *  Copyright (C) 2021  Double Bastion LLC
4
+ *
5
+ *  This file is part of Roundpin, which is licensed under the
6
+ *  GNU Affero General Public License Version 3.0. The license terms
7
+ *  are detailed in the "LICENSE.txt" file located in the root directory.
8
+ *
9
+ *  This is a modified version of the original file "index.html",
10
+ *  first modified in 2020. The copyright notice for the original
11
+ *  content follows:
12
+
13
+/*
14
+  Cyber Mega Phone 2K
15
+  Copyright (C) 2017 Digium, Inc.
16
+
17
+  This program is free software, distributed under the terms of the
18
+  MIT License. See the LICENSE file at the top of the source tree.
19
+*/
20
+
21
+$retrievedstringinit = $_GET['param'];
22
+$retrievedstring = hex2bin($retrievedstringinit);
23
+
24
+if ($retrievedstring != '') {
25
+
26
+    session_start();
27
+
28
+    define('ACCESSCONST', TRUE);
29
+
30
+    require('../db-connect.php');
31
+
32
+    // Extract the secret from the configuration file
33
+    $configfilestring = file_get_contents('../roundpin-config.php'); 
34
+
35
+    if (preg_match_all('[include|include_once|require|require_once]', $configfilestring) != 0) {
36
+
37
+        if (strpos($configfilestring, "'") !== false) {
38
+            $continit = explode("'", $configfilestring);
39
+            $configfilepath = $continit[1];
40
+        } elseif (strpos($configfilestring, "\"") !== false) {
41
+            $continit = explode("\"", $configfilestring);
42
+            $configfilepath = $continit[1];
43
+          }
44
+
45
+        $configfilelines = file($configfilepath);
46
+
47
+        if (count($configfilelines) != 0) {
48
+
49
+           foreach ($configfilelines as $keyfile => $valuefile) {
50
+
51
+              if (strpos($valuefile, "\$secret") !== false) {
52
+                  $secret_init = explode("'", $valuefile);
53
+                  $secretfin = $secret_init[1];
54
+              }
55
+           }
56
+        }
57
+
58
+    } else {
59
+
60
+        $configfilelines = file('../roundpin-config.php');
61
+
62
+        if (count($configfilelines) != 0) {
63
+           foreach ($configfilelines as $keyfile => $valuefile) {
64
+              if (strpos($valuefile, "\$secret") !== false) {
65
+                  $secretinit = explode("'", $valuefile);
66
+                  $secretfin = $secretinit[1];
67
+              }
68
+           }
69
+        }
70
+      }
71
+
72
+    // Decrypt the extension used for external access to conference and the username of the user who created the link
73
+    $componentuserext = explode(':', $retrievedstring);
74
+
75
+    $encpwdinusext = $componentuserext[0];
76
+    $ivkey = $componentuserext[1];
77
+
78
+    $userExtDec = openssl_decrypt($encpwdinusext, 'AES-256-CBC', $secretfin, false, $ivkey);
79
+
80
+    $userExtDecComp = explode("|", $userExtDec);
81
+    $userName = $userExtDecComp[0];
82
+    $extForExtern = $userExtDecComp[1];
83
+
84
+    $retrievedSipUsername = $extForExtern;
85
+
86
+    // Get the relevant information for the superadmin who created the external access link
87
+    $query1 = $mysqli->query("SELECT id, userrole, username, wss_server, stun_server, video_conf_extension, enabled FROM app_users WHERE userrole = 'superadmin' AND BINARY username = '$userName' AND enabled = 1");
88
+    $queryres = $query1->fetch_array();
89
+    $userID = $queryres[0];
90
+    $retrievedWssServer = $queryres[3];
91
+    $retrievedStunServer = $queryres[4];
92
+    $retrievedVideoConfExt = $queryres[5];
93
+
94
+    // Get the SIP password from the 'external_users' table
95
+    $query2 = $mysqli->query("SELECT id, userid, exten_for_external, exten_for_ext_pass FROM external_users WHERE userid = '$userID' AND exten_for_external = '$extForExtern'");
96
+    $extqueryres = $query2->fetch_array();
97
+    $extensionPass = $extqueryres[3];
98
+
99
+    // Decrypt the SIP password
100
+    $componentpkey = explode(':', $extensionPass);
101
+    $psswdaddedkey = file_get_contents('../restr/'.$userName.'/externalext/'.$extForExtern);
102
+
103
+    $encpwdinsip = $componentpkey[0];
104
+    $ivkeysip = $componentpkey[1];
105
+
106
+    $retrievedSipPassword = openssl_decrypt($encpwdinsip, 'AES-256-CBC', $psswdaddedkey, false, $ivkeysip);
107
+
108
+?>
109
+
110
+<!DOCTYPE html>
111
+
112
+<html>
113
+<head>
114
+    <meta charset="utf-8" />
115
+    <title>Roundpin Video Conference</title>
116
+    <link rel="stylesheet" type="text/css" href="css/conference-phone.min.css">
117
+
118
+    <link rel="stylesheet" type="text/css" href="../fonts/font-awesome-4.7.0/css/font-awesome.min.css"/>
119
+
120
+    <link rel="stylesheet" type="text/css" href="../css/jeegoo-1.0.0.min.css"/>
121
+
122
+    <link rel="shortcut icon" type="image/svg" href="../images/favicon.svg" />
123
+    <script type="text/javascript" src="js/sdp-interop-sl-1.4.0.min.js"></script>
124
+    <script type="text/javascript" src="js/jssip-3.7.0.min.js"></script>
125
+    <script type="text/javascript" src="js/utils.min.js"></script>
126
+    <script type="text/javascript" src="../js/jquery-3.3.1.min.js"></script>
127
+
128
+    <script type="text/javascript" src="js/conference-phone.min.js"></script>
129
+
130
+    <script type="text/javascript" src="../js/jquery.jeegoopopup.1.0.0.min.js"></script>
131
+
132
+<script type="text/javascript">
133
+
134
+let phone;
135
+let numPressed = null;
136
+
137
+let sip_username = "<?php print_r($retrievedSipUsername); ?>";
138
+let sip_password = "<?php print_r($retrievedSipPassword); ?>";
139
+let wss_server = "<?php print_r($retrievedWssServer); ?>";
140
+let stun_server = "<?php print_r($retrievedStunServer); ?>";
141
+let videoConfExtension = "<?php print_r($retrievedVideoConfExt); ?>";
142
+
143
+window.onload = function() {
144
+
145
+        var mvcount = 0;
146
+	document.getElementById("connect").value = "Connect";
147
+	document.getElementById("connect").disabled = false;
148
+	document.getElementById("call").value = "Call";
149
+	document.getElementById("call").disabled = true;
150
+        document.getElementById("call").style.display = 'none';
151
+        document.getElementById("fullscreen").style.display = 'none';
152
+
153
+	function findMediaView(parent, stream) {
154
+		let nodes = parent.childNodes;
155
+
156
+		for (let i = 0; i < nodes.length; ++i) {
157
+			if (nodes[i].id == stream.id) {
158
+				return nodes[i];
159
+			}
160
+		}
161
+		return null;
162
+	}
163
+
164
+        function dtmfMenuShow() {
165
+
166
+                $.jeegoopopup.close();
167
+
168
+	        var leftPos = event.pageX - 90;
169
+	        var topPos = event.pageY + 28;
170
+
171
+		if ($(window).width() < 680) {
172
+		    leftPos = event.pageX - 50;
173
+		}
174
+
175
+	        var html = "<div id=\"sendPinDialPad\">";
176
+	        html += "<div><input type=\"text\" id=\"dialText\" class=\"dialTextInput\"></div>";
177
+	        html += "<table cellspacing=10 cellpadding=0 style=\"margin-left:auto; margin-right: auto\">";
178
+	        html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('1');new Audio('../sounds/dtmf.mp3').play();\"><div>1</div><span>&nbsp;</span></button></td>";
179
+	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('2');new Audio('../sounds/dtmf.mp3').play();\"><div>2</div><span>ABC</span></button></td>";
180
+	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('3');new Audio('../sounds/dtmf.mp3').play();\"><div>3</div><span>DEF</span></button></td></tr>";
181
+	        html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('4');new Audio('../sounds/dtmf.mp3').play();\"><div>4</div><span>GHI</span></button></td>";
182
+	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('5');new Audio('../sounds/dtmf.mp3').play();\"><div>5</div><span>JKL</span></button></td>";
183
+	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('6');new Audio('../sounds/dtmf.mp3').play();\"><div>6</div><span>MNO</span></button></td></tr>";
184
+	        html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('7');new Audio('../sounds/dtmf.mp3').play();\"><div>7</div><span>PQRS</span></button></td>";
185
+	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('8');new Audio('../sounds/dtmf.mp3').play();\"><div>8</div><span>TUV</span></button></td>";
186
+	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('9');new Audio('../sounds/dtmf.mp3').play();\"><div>9</div><span>WXYZ</span></button></td></tr>";
187
+	        html += "<tr><td><button class=dtmfButtons onclick=\"phone.dtmfSend('*');new Audio('../sounds/dtmf.mp3').play();\">*</button></td>";
188
+	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('0');new Audio('../sounds/dtmf.mp3').play();\">0</button></td>";
189
+	        html += "<td><button class=dtmfButtons onclick=\"phone.dtmfSend('#');new Audio('../sounds/dtmf.mp3').play();\">#</button></td></tr>";
190
+	        html += "</table>";
191
+	        html += "</div>";
192
+
193
+	        $.jeegoopopup.open({
194
+			html: html,
195
+			width: "auto",
196
+			height: "auto",
197
+			left: leftPos,
198
+			top: topPos,
199
+			scrolling: 'no',
200
+			skinClass: 'jg_popup_basic',
201
+			overlay: true,
202
+			opacity: 0,
203
+			draggable: true,
204
+			resizable: false,
205
+			fadeIn: 0
206
+	        });
207
+
208
+	        $("#jg_popup_overlay").click(function() { $.jeegoopopup.close(); });
209
+	        $(window).on('keydown', function(event) { if (event.key == "Escape") { $.jeegoopopup.close(); } });
210
+        }
211
+
212
+	function createMediaControls(video) {
213
+
214
+		let controls = document.createElement("div");
215
+		controls.className = "media-controls";
216
+
217
+                if (video.srcObject.local == true) {
218
+		        let sendPin = document.createElement("button");
219
+                        sendPin.className = "mediaControlBtn";
220
+                        sendPin.id = "sendPinBtn";
221
+		        sendPin.innerHTML = '<i class="fa fa-keyboard-o" aria-hidden="true" title="Show Keypad"></i>';
222
+                        sendPin.onclick = function() { dtmfMenuShow(); }
223
+
224
+		        controls.appendChild(sendPin);
225
+                }
226
+
227
+		let audioTracks = video.srcObject.getAudioTracks();
228
+		if (audioTracks.length > 0) {
229
+                        let muteAudio = document.createElement("button");
230
+                        muteAudio.className = "mediaControlBtn";
231
+                        muteAudio.innerHTML = '<i class="fa fa-microphone-slash" aria-hidden="true" title="Mute Audio"></i>';
232
+			muteAudio.setAttribute("state", "Unmute");
233
+			muteAudio.onclick = function() {
234
+				let state = this.getAttribute("state");
235
+                                if (state == "Mute") {
236
+                                    this.setAttribute("state", "Unmute");
237
+                                    this.innerHTML = '<i class="fa fa-microphone-slash" aria-hidden="true" title="Mute Audio"></i>';
238
+                                } else if (state == "Unmute") {
239
+                                    this.setAttribute("state", "Mute");
240
+                                    this.innerHTML = '<i class="fa fa-microphone" aria-hidden="true" title="Unmute Audio"></i>';
241
+                                }
242
+
243
+				mute(video.srcObject, {audio: this.getAttribute("state") == "Mute"});
244
+			};
245
+			controls.appendChild(muteAudio);
246
+		}
247
+
248
+		let videoTracks = video.srcObject.getVideoTracks();
249
+		if (videoTracks.length > 0) {
250
+                        let muteVideo = document.createElement("button");
251
+                        muteVideo.className = "mediaControlBtn";
252
+                        muteVideo.innerHTML = '<i class="fa fa-ban" aria-hidden="true" title="Mute Video"></i>';
253
+			muteVideo.setAttribute("state", "Unmute");
254
+			muteVideo.onclick = function() {
255
+				let state = this.getAttribute("state");
256
+                                if (state == "Mute") {
257
+                                    this.setAttribute("state", "Unmute");
258
+                                    this.innerHTML = '<i class="fa fa-ban" aria-hidden="true" title="Mute Video"></i>';
259
+                                } else if (state == "Unmute") {
260
+                                    this.setAttribute("state", "Mute");
261
+                                    this.innerHTML = '<i class="fa fa-video-camera" aria-hidden="true" title="Unmute Video"></i>';
262
+                                }
263
+
264
+				mute(video.srcObject, {video: this.getAttribute("state") == "Mute"});
265
+			};
266
+			controls.appendChild(muteVideo);
267
+
268
+                        if (video.srcObject.local == true) {
269
+                                let ScreenShare = document.createElement("button");
270
+                                ScreenShare.className = "mediaControlBtn";
271
+                                ScreenShare.innerHTML = '<i class="fa fa-desktop" aria-hidden="true" title="Share Screen"></i>';
272
+				ScreenShare.onclick = function() {
273
+					phone.ShareScreen();
274
+				};
275
+
276
+				controls.appendChild(ScreenShare);
277
+
278
+                                let VideoShare = document.createElement("button");
279
+                                VideoShare.className = "mediaControlBtn";
280
+                                VideoShare.innerHTML = '<i class="fa fa-video-camera" aria-hidden="true" title="Share Camera"></i>';
281
+				VideoShare.onclick = function() {
282
+					phone.ShareVideo();
283
+				};
284
+
285
+				controls.appendChild(VideoShare);
286
+                        }
287
+
288
+                        let fullScreen = document.createElement("button");
289
+                        fullScreen.className = "mediaControlBtn";
290
+                        fullScreen.innerHTML = '<i class="fa fa-expand" aria-hidden="true" title="Full Screen"></i>';
291
+			fullScreen.onclick = function() {
292
+			    this.fullScreen.request();					
293
+			};
294
+
295
+			fullScreen.fullScreen = new FullScreen(video);
296
+			controls.appendChild(fullScreen);
297
+		}
298
+		return controls;
299
+	}
300
+
301
+	function createMediaView(stream) {
302
+
303
+		var mediaView = document.createElement("div");
304
+		mediaView.className = "media-view";
305
+		mediaView.id = "new-media-view"+stream.id;
306
+                mediaView.style.width = localStorage.getItem("VidConfWindowWidth")+"%";
307
+
308
+		var videoView = document.createElement("div");
309
+                videoView.className = "video-view";
310
+                videoView.id = "video-view"+stream.id;
311
+
312
+		var video = document.createElement("video");
313
+                video.className = "videoElem";
314
+                video.id = "locVideo"+stream.id;
315
+		video.autoplay = true;
316
+
317
+		video.srcObject = stream;
318
+		video.onloadedmetadata = function() {
319
+		      let tracks = stream.getVideoTracks();
320
+
321
+		      for (let i = 0; i < tracks.length; ++i) {
322
+			   tracks[i].enabled = true;
323
+		      }
324
+		};
325
+
326
+		if (stream.local == false) {
327
+			function checkForVideo() {
328
+				if (video.videoWidth < 10 || video.videoHeight < 10) {
329
+                                    mediaView.style.display = 'none';
330
+				    return;
331
+				}
332
+                                mediaView.style.display = 'inline';
333
+			}
334
+                        checkForVideo();
335
+			setInterval(checkForVideo, 1000);
336
+		}
337
+
338
+		// Video elements connected to local streams will by default
339
+		// echo both the video and the audio back to ourselves. Since
340
+		// we don't want to hear ourselves we mute it, which mutes only
341
+		// the audio portion.
342
+
343
+		if (stream.local == true) {
344
+			video.muted = true;
345
+		} else if (mvcount == 0) {
346
+                        // We hide our own remote video track
347
+                        mvcount = 1;
348
+                        document.getElementById(mediaView.id).style.display = 'none';
349
+                }
350
+
351
+		videoView.appendChild(video);
352
+		mediaView.appendChild(videoView);
353
+		mediaView.appendChild(createMediaControls(video));
354
+
355
+		return mediaView;
356
+	}
357
+
358
+	function removeMediaView(parent, stream) {
359
+		let node = findMediaView(parent, stream);
360
+		if (node) {
361
+			parent.removeChild(node);
362
+		}
363
+	}
364
+
365
+	function getValue(id) {
366
+		let obj = document.getElementById(id);
367
+		return obj.value ? obj.value : obj.placeholder;
368
+	}
369
+
370
+        document.getElementById("connect").addEventListener("click", function() {
371
+		if (document.getElementById("connect").value == "Disconnect") {
372
+			document.getElementById("call").value = "Call";
373
+			document.getElementById("call").disabled = true;
374
+			document.getElementById("connect").value = "Disconnecting";
375
+			document.getElementById("connect").disabled = true;
376
+
377
+			phone.disconnect();
378
+			return;
379
+		}
380
+
381
+                phone = new ConferencePhone(sip_username, sip_username, sip_password, wss_server, stun_server, true);
382
+
383
+                sip_password = '';
384
+
385
+		phone.handle("connected", function () {
386
+
387
+			if (document.getElementById("connect").value != "Disconnect") {
388
+				document.getElementById("connect").value = "Registering";
389
+			} else {
390
+				document.getElementById("connect").value = "Disconnect";
391
+				document.getElementById("connect").disabled = false;
392
+				document.getElementById("call").disabled = false;
393
+			}
394
+		});
395
+
396
+		phone.handle("disconnected", function () {
397
+			document.getElementById("connect").value = "Connect";
398
+			document.getElementById("connect").disabled = false;
399
+			document.getElementById("call").value = "Call";
400
+			document.getElementById("call").disabled = true;
401
+		});
402
+
403
+		phone.handle("registered", function () {
404
+			document.getElementById("connect").value = "Disconnect";
405
+			document.getElementById("connect").disabled = false;
406
+			document.getElementById("call").disabled = false;
407
+		});
408
+
409
+		phone.handle("registrationFailed", function () {
410
+			phone.disconnect();
411
+		});
412
+
413
+		phone.handle("incoming", function (reason) {
414
+			document.getElementById("call").value = "Answer";
415
+		});
416
+
417
+		phone.handle("failed", function (reason) {
418
+			document.getElementById("call").value = "Call";
419
+			document.getElementById("call").disabled = false;
420
+		});
421
+
422
+		phone.handle("ended", function (reason) {
423
+			document.getElementById("call").value = "Call";
424
+			document.getElementById("call").disabled = document.getElementById("connect").value == "Connect";
425
+		});
426
+
427
+		phone.handle("streamAdded", function (stream) {
428
+			document.getElementById("media-views").appendChild(createMediaView(stream));
429
+			document.getElementById("call").value = "Hangup";
430
+			document.getElementById("call").disabled = false;
431
+                        document.getElementById("call").style.display = 'inline';
432
+                        document.getElementById("fullscreen").style.display = 'inline';
433
+                        document.getElementById("fullscreen").innerHTML = '<i class="fa fa-expand" aria-hidden="true"></i><b>&nbsp; Fullscreen';
434
+		});
435
+
436
+		phone.handle("streamRemoved", function (stream) {
437
+			removeMediaView(document.getElementById("media-views"), stream);
438
+		});
439
+
440
+		phone.connect();
441
+
442
+		document.getElementById("connect").disabled = true;
443
+		document.getElementById("connect").value = "Connecting";
444
+	});
445
+
446
+        document.getElementById("connect").click();
447
+
448
+        let constraints = { video: true, audio: true };
449
+        navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
450
+            phone.call(videoConfExtension);
451
+        }).catch(function(err) { });
452
+
453
+        let node = document.getElementById("call");
454
+
455
+        if (node.value == "Answer") {
456
+	    node.disabled = true;
457
+	    node.value = "Hangup";
458
+	}
459
+
460
+        document.getElementById("call").addEventListener("click", function() {
461
+            if (node.value == "Hangup") {
462
+	        phone.terminate();
463
+                document.getElementById("call").remove();
464
+                window.close();
465
+                document.getElementsByTagName("body")[0].innerHTML = '<h4 style="text-align:center;color:#595959;">You have closed the video conference call ! If you want to enter the conference again, just press the button from below:</h4><button class="enterConfExt" onclick="window.location.reload()">Enter Conference Again</button><h4 style="text-align:center;color:#595959;">Otherwise, you can close this browser tab.</h4>';
466
+            }
467
+        });
468
+
469
+	$("#showConnectionBttns").click(function() {
470
+	  if ($("#connection").is(':visible')) {
471
+	      $("#connection").hide();
472
+	      $("#showConnectionBttns").html('<i class="fa fa-caret-down" aria-hidden="true"></i>');
473
+	  } else { 
474
+	      $("#connection").show();
475
+	      $("#showConnectionBttns").html('<i class="fa fa-caret-up" aria-hidden="true"></i>');
476
+	  }
477
+	});
478
+
479
+	document.addEventListener("fullscreenchange", onFullScreenChange, false);
480
+	document.addEventListener("webkitfullscreenchange", onFullScreenChange, false);
481
+	document.addEventListener("mozfullscreenchange", onFullScreenChange, false);
482
+
483
+	function onFullScreenChange() {
484
+	   if (document.mozFullScreenElement != null || document.webkitFullscreenElement != null || document.fullscreenElement != null) {
485
+	       document.getElementById("fullscreen").innerHTML = '<i class="fa fa-compress" aria-hidden="true"></i><b>&nbsp; Exit Fullscreen';
486
+	       document.getElementById("fullscreen").style.width = "148px";
487
+	   } else { 
488
+	       document.getElementById("fullscreen").innerHTML = '<i class="fa fa-expand" aria-hidden="true"></i><b>&nbsp; Fullscreen';
489
+	       document.getElementById("fullscreen").style.width = "117px";
490
+	   }
491
+	}
492
+
493
+}; // window.onload
494
+
495
+window.onbeforeunload = function() {
496
+       phone.terminate();
497
+}; 
498
+
499
+window.onunload = function() {
500
+       if (phone) {
501
+	   phone.disconnect();
502
+       }
503
+}; // window.onunload
504
+
505
+</script>
506
+</head>
507
+<body>
508
+	<div id="connection">
509
+               <div id="VideoConferenceLogo"><img src="../images/small-logo.svg" /></div>
510
+	       <input type="button" id="connect" class="connect" value="Connect" style="display:none;" />
511
+               <button id="call" class="call"><i class="fa fa-phone" aria-hidden="true"></i><b>&nbsp; Hangup</b></button>
512
+               <button id="fullscreen" class="fullscreen" onclick="toggleFullScreen(document.body)"><i class="fa fa-expand" aria-hidden="true"></i><b>&nbsp; Fullscreen</b></button>
513
+	</div>
514
+        <div id="showConnectionBttns"><i class="fa fa-caret-down" aria-hidden="true"></i></div>
515
+       <div id="media-views" class="media-views"></div>
516
+
517
+<script type="text/javascript">
518
+
519
+FullScreen.prototype.request = function() {
520
+	if (this.is()) {
521
+		return;
522
+	}
523
+
524
+	if (this._obj.requestFullscreen) {
525
+		this._obj.requestFullscreen();
526
+	} else if (this._obj.mozRequestFullScreen) {
527
+		this._obj.mozRequestFullScreen();
528
+	} else if (this._obj.webkitRequestFullScreen) {
529
+		this._obj.webkitRequestFullScreen();
530
+	} else if (this._obj.msRequestFullscreen) {
531
+		this._obj.msRequestFullscreen();
532
+	}
533
+
534
+	this.setData(true);
535
+};
536
+
537
+function toggleFullScreen(elem) {
538
+
539
+    if ((document.fullScreenElement !== undefined && document.fullScreenElement === null) || (document.msFullscreenElement !== undefined && document.msFullscreenElement === null) ||
540
+       (document.mozFullScreen !== undefined && !document.mozFullScreen) || (document.webkitIsFullScreen !== undefined && !document.webkitIsFullScreen)) {
541
+        if (elem.requestFullScreen) {
542
+            elem.requestFullScreen();
543
+        } else if (elem.mozRequestFullScreen) {
544
+            elem.mozRequestFullScreen();
545
+        } else if (elem.webkitRequestFullScreen) {
546
+            elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
547
+        } else if (elem.msRequestFullscreen) {
548
+            elem.msRequestFullscreen();
549
+        }
550
+
551
+    } else {
552
+        if (document.cancelFullScreen) {
553
+            document.cancelFullScreen();
554
+        } else if (document.mozCancelFullScreen) {
555
+            document.mozCancelFullScreen();
556
+        } else if (document.webkitCancelFullScreen) {
557
+            document.webkitCancelFullScreen();
558
+        } else if (document.msExitFullscreen) {
559
+            document.msExitFullscreen();
560
+        }
561
+    }
562
+}
563
+
564
+</script>
565
+</body>
566
+</html>
567
+
568
+<?php
569
+
570
+} else {
571
+     header("Location: ../roundpin-login.php");
572
+  }
573
+
574
+?>