index.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. <?php
  2. /*
  3. FusionPBX
  4. Version: MPL 1.1
  5. The contents of this file are subject to the Mozilla Public License Version
  6. 1.1 (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.mozilla.org/MPL/
  9. Software distributed under the License is distributed on an "AS IS" basis,
  10. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. for the specific language governing rights and limitations under the
  12. License.
  13. The Original Code is FusionPBX
  14. The Initial Developer of the Original Code is
  15. Mark J Crane <[email protected]>
  16. Portions created by the Initial Developer are Copyright (C) 2018
  17. the Initial Developer. All Rights Reserved.
  18. */
  19. //includes files
  20. require_once dirname(__DIR__, 2) . "/resources/require.php";
  21. require_once "resources/check_auth.php";
  22. //check permissions
  23. if (permission_exists('extension_add') || permission_exists('extension_edit')) {
  24. //access granted
  25. }
  26. else {
  27. echo "access denied";
  28. exit;
  29. }
  30. //add multi-lingual support
  31. $language = new text;
  32. $text = $language->get();
  33. //get the user ID
  34. $sql = "SELECT d.domain_name,e.extension,e.password FROM ";
  35. $sql .= "v_extension_users as t, v_extensions as e, v_users as u, v_domains as d ";
  36. $sql .= "WHERE u.user_uuid = t.user_uuid ";
  37. $sql .= "AND e.extension_uuid = t.extension_uuid ";
  38. $sql .= "AND e.domain_uuid = d.domain_uuid ";
  39. $sql .= "AND u.user_uuid = '" . $_SESSION['user_uuid'] . "' ";
  40. $sql .= "AND e.domain_uuid = '" . $_SESSION["domain_uuid"] . "' LIMIT 1";
  41. $prep_statement = $db->prepare($sql);
  42. if ($prep_statement) {
  43. $prep_statement->execute();
  44. $row = $prep_statement->fetch(PDO::FETCH_ASSOC);
  45. $domain_name = $row['domain_name'];
  46. $user_extension = $row['extension'];
  47. $user_password = $row['password'];
  48. }
  49. //show the header
  50. require_once "resources/header.php";
  51. ?>
  52. <style type="text/css">
  53. body {
  54. background-color: #333;
  55. }
  56. .inner {
  57. position: absolute;
  58. }
  59. .buttons{
  60. position: fixed;
  61. bottom: 0;
  62. right: 0;
  63. /*width: 200px;*/
  64. border: 10px solid rgba(255, 255, 255, 0);
  65. }
  66. </style>
  67. <div class="">
  68. <div style="position: absolute;"><video id="remote_video" width="640" height="480" style="display: none;"></video></div>
  69. <div style="position: absolute;display: none;"><video id="local_video" width="160" height="120" style="display: none;"></video></div>
  70. <!--<input id='send' name="send" type="button" class='btn btn-success' onclick="send();" value="Send" />-->
  71. </div>
  72. <audio id="ringtone" preload="auto" style="display: none;">
  73. <source src="resources/ringtones/ringtone.mp3" type="audio/mpeg" loop="loop" />
  74. </audio>
  75. <script src="sip-0.7.8.min.js"></script>
  76. <!--<script src="./resources/sip-0.21.2.js"></script>-->
  77. <!--<script type="module" src="./resources/app.php"></script>-->
  78. <script language="JavaScript" type="text/javascript">
  79. function sanitize_string(str) {
  80. let temp = document.createElement('div');
  81. temp.textContent = str;
  82. return temp.innerHTML;
  83. }
  84. <?php
  85. echo " let user_agent;\n";
  86. echo " let session;\n";
  87. echo " let answer_time;\n";
  88. echo " var config = {\n";
  89. echo " uri: '".$user_extension."@".$domain_name."',\n";
  90. echo " ws_servers: 'wss://".$domain_name.":7443',\n";
  91. echo " authorizationUser: '".$user_extension."',\n";
  92. echo " password: atob('".base64_encode($user_password)."'),\n";
  93. echo " registerExpires: 120,\n";
  94. echo " displayName: \"".$user_extension."\"\n";
  95. echo " };\n";
  96. ?>
  97. user_agent = new SIP.UA(config);
  98. //here you determine whether the call has video and audio
  99. var options = {
  100. media: {
  101. constraints: {
  102. audio: true,
  103. video: false
  104. },
  105. render: {
  106. remote: document.getElementById('remote_video'),
  107. local: document.getElementById('local_video')
  108. },
  109. RTCConstraints: {
  110. "optional": [{ 'DtlsSrtpKeyAgreement': 'true'} ]
  111. }
  112. }
  113. };
  114. //answer
  115. user_agent.on('invite', function (s) {
  116. if (typeof session !== "undefined" && session.display_name != s.remoteIdentity.displayName) {
  117. return;
  118. }
  119. //save the session to the global session
  120. session = s;
  121. session.display_name = session.remoteIdentity.displayName;
  122. session.uri_user = session.remoteIdentity.uri.user;
  123. //send the object to the browser console
  124. //console.log(session);
  125. //play the ringtone
  126. document.getElementById('ringtone').play();
  127. //add the caller ID
  128. document.getElementById('ringing_caller_id').innerHTML = sanitize_string(session.display_name) + "<br /><a href='https://<?php echo $_SESSION['domain_name']; ?>/app/contacts/contacts.php?search=" + sanitize_string(session.uri_user) + "' target='_blank'>" + sanitize_string(session.uri_user) + "</a>";
  129. document.getElementById('active_caller_id').innerHTML = sanitize_string(session.display_name) + "<br /><a href='https://<?php echo $_SESSION['domain_name']; ?>/app/contacts/contacts.php?search=" + sanitize_string(session.uri_user) + "' target='_blank'>" + sanitize_string(session.uri_user) + "</a>";
  130. //show or hide the panels
  131. document.getElementById('dialpad').style.display = "none";
  132. document.getElementById('ringing').style.display = "inline";
  133. //show or hide the buttons
  134. document.getElementById('answer').style.display = "inline";
  135. document.getElementById('decline').style.display = "inline";
  136. document.getElementById('hangup').style.display = "none";
  137. document.getElementById('mute_audio').style.display = "inline";
  138. document.getElementById('mute_video').style.display = "none";
  139. session.on('cancel', function (s) {
  140. //play the ringtone
  141. document.getElementById('ringtone').pause();
  142. //show or hide the panels
  143. document.getElementById('dialpad').style.display = "grid";
  144. document.getElementById('ringing').style.display = "none";
  145. document.getElementById('active').style.display = "none";
  146. //show or hide the buttons
  147. document.getElementById('answer').style.display = "none";
  148. document.getElementById('decline').style.display = "none";
  149. document.getElementById('hangup').style.display = "none";
  150. //clear the caller id
  151. document.getElementById('ringing_caller_id').innerHTML = '';
  152. document.getElementById('active_caller_id').innerHTML = '';
  153. //clear the answer time
  154. answer_time = null;
  155. });
  156. session.on('bye', function (s) {
  157. //play the ringtone
  158. document.getElementById('ringtone').pause();
  159. //show or hide the panels
  160. document.getElementById('dialpad').style.display = "grid";
  161. document.getElementById('ringing').style.display = "none";
  162. document.getElementById('active').style.display = "none";
  163. //show or hide the buttons
  164. document.getElementById('answer').style.display = "none";
  165. document.getElementById('decline').style.display = "none";
  166. document.getElementById('hangup').style.display = "none";
  167. //clear the answer time
  168. answer_time = null;
  169. //end the call
  170. hangup();
  171. });
  172. session.on('failed', function (s) {
  173. //play the ringtone
  174. document.getElementById('ringtone').pause();
  175. //show or hide the panels
  176. document.getElementById('dialpad').style.display = "grid";
  177. document.getElementById('ringing').style.display = "none";
  178. document.getElementById('active').style.display = "none";
  179. //show or hide the buttons
  180. document.getElementById('answer').style.display = "none";
  181. document.getElementById('decline').style.display = "none";
  182. document.getElementById('hangup').style.display = "none";
  183. //clear the answer time
  184. answer_time = null;
  185. //end the call
  186. hangup();
  187. });
  188. session.on('rejected', function (s) {
  189. //play the ringtone
  190. document.getElementById('ringtone').pause();
  191. //show or hide the panels
  192. document.getElementById('dialpad').style.display = "grid";
  193. document.getElementById('ringing').style.display = "none";
  194. document.getElementById('active').style.display = "none";
  195. //show or hide the buttons
  196. document.getElementById('answer').style.display = "none";
  197. document.getElementById('decline').style.display = "none";
  198. document.getElementById('hangup').style.display = "none";
  199. //clear the answer time
  200. answer_time = null;
  201. //end the call
  202. hangup();
  203. });
  204. });
  205. function answer() {
  206. //continue if the session exists
  207. if (!session) {
  208. return false;
  209. }
  210. //start the answer time
  211. answer_time = Date.now();
  212. //pause the ringtone
  213. document.getElementById('ringtone').pause();
  214. //answer the call
  215. session.accept({
  216. media: {
  217. constraints: {
  218. audio: true,
  219. video: false
  220. },
  221. render: {
  222. remote: document.getElementById('remote_video'),
  223. local: document.getElementById('local_video')
  224. },
  225. RTCConstraints: {
  226. "optional": [{ 'DtlsSrtpKeyAgreement': 'true'} ]
  227. }
  228. }
  229. });
  230. //show the or hide the panels
  231. document.getElementById('dialpad').style.display = "none";
  232. document.getElementById('ringing').style.display = "none";
  233. document.getElementById('active').style.display = "grid";
  234. //show or hide the buttons
  235. document.getElementById('answer').style.display = "none";
  236. document.getElementById('decline').style.display = "none";
  237. document.getElementById('unhold').style.display = "none";
  238. document.getElementById('hangup').style.display = "inline";
  239. }
  240. // Function to pad numbers with leading zeros
  241. function pad(number, length) {
  242. return (number < 10 ? '0' : '') + number;
  243. }
  244. //function to get the current time in seconds
  245. function get_session_time() {
  246. if (answer_time) {
  247. // get the elapsed time using the answer time
  248. elapsed_time = Date.now() - answer_time;
  249. // Calculate hours, minutes, and seconds
  250. var hours = Math.floor(elapsed_time / (1000 * 60 * 60));
  251. var minutes = Math.floor((elapsed_time % (1000 * 60 * 60)) / (1000 * 60));
  252. var seconds = Math.floor((elapsed_time % (1000 * 60)) / 1000);
  253. // Format the time with leading zeros if necessary
  254. var formatted_time = pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2);
  255. // Update the element with id="elapsed-time" to display the formatted elapsed time
  256. document.getElementById("answer_time").textContent = "Time Elapsed: " + formatted_time;
  257. } else {
  258. console.log('Call has not been answered yet');
  259. return null;
  260. }
  261. }
  262. //update elapsed time every second
  263. setInterval(get_session_time, 1000);
  264. //function used to end the session
  265. function hangup() {
  266. //session.bye();
  267. session.terminate();
  268. //show or hide the panels
  269. document.getElementById('dialpad').style.display = "grid";
  270. document.getElementById('ringing').style.display = "none";
  271. document.getElementById('active').style.display = "none";
  272. //show or hide the buttons
  273. document.getElementById('answer').style.display = "none";
  274. document.getElementById('decline').style.display = "none";
  275. document.getElementById('hangup').style.display = "none";
  276. document.getElementById('local_video').style.display = "none";
  277. document.getElementById('remote_video').style.display = "none";
  278. document.getElementById('mute_audio').style.display = "none";
  279. document.getElementById('mute_video').style.display = "none";
  280. document.getElementById('unmute_audio').style.display = "none";
  281. document.getElementById('unmute_video').style.display = "none";
  282. //clear the caller id
  283. document.getElementById('ringing_caller_id').innerHTML = '';
  284. document.getElementById('active_caller_id').innerHTML = '';
  285. }
  286. function hold() {
  287. document.getElementById('hold').style.display = "none";
  288. document.getElementById('unhold').style.display = "grid";
  289. session.hold();
  290. }
  291. function unhold() {
  292. document.getElementById('hold').style.display = "grid";
  293. document.getElementById('unhold').style.display = "none";
  294. session.unhold();
  295. }
  296. function send() {
  297. //get the destination number
  298. destination = document.getElementById('destination').value;
  299. //return immediately if there is no destination
  300. if (destination.length == 0) {
  301. return;
  302. }
  303. //show or hide the panels
  304. document.getElementById('dialpad').style.display = "none";
  305. document.getElementById('ringing').style.display = "none";
  306. document.getElementById('active').style.display = "grid";
  307. document.getElementById('answer').style.display = "none";
  308. document.getElementById('decline').style.display = "none";
  309. document.getElementById('hangup').style.display = "inline";
  310. //document.getElementById('local_video').style.display = "inline";
  311. //document.getElementById('remote_video').style.display = "inline";
  312. document.getElementById('mute_audio').style.display = "inline";
  313. //document.getElementById('mute_video').style.display = "inline";
  314. //make a call using a sip invite
  315. session = user_agent.invite('sip:'+destination+'@<?php echo $domain_name; ?>', options);
  316. var remote_video = document.getElementById("remote_video");
  317. remote_video.setAttribute("controls","controls");
  318. //start the answer time
  319. answer_time = Date.now();
  320. //set the caller ID to the destination
  321. document.getElementById('ringing_caller_id').innerHTML = destination;
  322. document.getElementById('active_caller_id').innerHTML = destination;
  323. }
  324. function mute_audio(destination) {
  325. session.mute({audio: true});
  326. document.getElementById('mute_audio').style.display = "none";
  327. document.getElementById('unmute_audio').style.display = "inline";
  328. }
  329. function mute_video(destination) {
  330. session.mute({video: true});
  331. document.getElementById('local_video').style.display = "none";
  332. document.getElementById('mute_video').style.display = "none";
  333. document.getElementById('unmute_video').style.display = "inline";
  334. }
  335. function unmute_audio(destination) {
  336. session.unmute({audio: true});
  337. document.getElementById('mute_audio').style.display = "inline";
  338. document.getElementById('unmute_audio').style.display = "none";
  339. }
  340. function unmute_video(destination) {
  341. session.unmute({video: true});
  342. document.getElementById('local_video').style.display = "inline";
  343. document.getElementById('mute_video').style.display = "inline";
  344. document.getElementById('unmute_video').style.display = "none";
  345. }
  346. function digit_add($digit) {
  347. document.getElementById('destination').value = document.getElementById('destination').value + $digit;
  348. }
  349. function digit_delete($digit) {
  350. destination = document.getElementById('destination').value;
  351. document.getElementById('destination').value = destination.substring(0, destination.length -1);
  352. }
  353. function digit_clear($digit) {
  354. document.getElementById('destination').value = '';
  355. }
  356. //function to check for Enter key press
  357. function send_enter_key(event) {
  358. if (event.key === "Enter") {
  359. send();
  360. }
  361. }
  362. //add event listener for keydown event on input field
  363. document.addEventListener("DOMContentLoaded", function() {
  364. document.getElementById("destination").addEventListener("keydown", send_enter_key);
  365. });
  366. </script>
  367. <div id='dialpad' class='dialpad' style='position:absolute;z-index:999;'>
  368. <div style="align: left">
  369. <input type="text" id="destination" name="destination" class="destination" value="" />
  370. </div>
  371. <div class="dialpad_wrapper">
  372. <div class="dialpad_box" onclick="digit_add('1');"><strong>1</strong><sup>&nbsp;&nbsp;&nbsp;</sup></div>
  373. <div class="dialpad_box"onclick="digit_add('2');"><strong>2</strong><sup>ABC</sup></div>
  374. <div class="dialpad_box" onclick="digit_add('3');"><strong>3</strong><sup>DEF</sup></div>
  375. <div class="dialpad_box" onclick="digit_add('4');"><strong>4</strong><sup>GHI</sup></div>
  376. <div class="dialpad_box" onclick="digit_add('5');"><strong>5</strong><sup>JKL</sup></div>
  377. <div class="dialpad_box" onclick="digit_add('6');"><strong>6</strong><sup>MNO</sup></div>
  378. <div class="dialpad_box" onclick="digit_add('7');"><strong>7</strong><sup>PQRS</sup></div>
  379. <div class="dialpad_box" onclick="digit_add('8');"><strong>8</strong><sup>TUV</sup></div>
  380. <div class="dialpad_box" onclick="digit_add('9');"><strong>9</strong><sup>WXYZ</sup></div>
  381. <div class="dialpad_box" onclick="digit_add('*');"><strong>*</strong><sup></sup></div>
  382. <div class="dialpad_box" onclick="digit_add('0');"><strong>0</strong><sup></sup></div>
  383. <div class="dialpad_box" onclick="digit_add('#');"><strong>#</strong><sup></sup></div>
  384. <div class="dialpad_box" onclick="digit_clear();"><strong></strong><sup>CLEAR</sup></div>
  385. <div class="dialpad_box" onclick="digit_delete();"><strong></strong><sup>DELETE</sup></div>
  386. <div class="dialpad_box" onclick="send();"><strong></strong><sup>SEND</sup></div>
  387. </div>
  388. </div>
  389. <div id='ringing' class='dialpad' style='position:absolute;z-index:100;display: none;'>
  390. <div id="ringing_caller_id" class="caller_id"></div>
  391. <div class="dialpad_wrapper">
  392. <div id='answer' class="button_box" onclick="answer();"><sup>Answer</sup></div>
  393. <div id='decline' class="button_box" onclick="hangup();"><sup>Decline</sup></div>
  394. </div>
  395. </div>
  396. <div id='active' class='dialpad' style='position:absolute;z-index:100;display: none;'>
  397. <div id="active_caller_id" class="caller_id"></div>
  398. <div id="answer_time" class="button_box"></div>
  399. <div class="dialpad_wrapper">
  400. <div id='mute_audio' class="button_box" onclick="mute_audio();">Mute Audio</div>
  401. <div id='unmute_audio' style='display: none;' class="button_box" onclick="unmute_audio();">Unmute Audio</div>
  402. <div id='hold' class="button_box" onclick="hold();">Hold</div>
  403. <div id='unhold' class="button_box" style='display: none;' onclick="unhold();">Unhold</div>
  404. <div id='hangup' class="button_box" onclick="hangup();">Hangup</div>
  405. <div id='mute_video' class="button_box" style='display: none;' onclick="mute_video()">&nbsp;</div>
  406. <div id='umute_video' class="button_box" style='display: none;' onclick="unmute_video()">&nbsp;</div>
  407. </div>
  408. </div>
  409. <style type="text/css" style="display: none;">
  410. .destination {
  411. /*background-color: #333333;*/
  412. background-color: rgba(255, 255, 255, 0.5);
  413. color: #333333;
  414. border-radius: 5px;
  415. padding: 10px;
  416. margin: 3px;
  417. width: 305px;
  418. }
  419. .dialpad_wrapper {
  420. display: grid;
  421. grid-template-columns: 100px 100px 100px;
  422. grid-gap: 5px;
  423. color: #444444;
  424. }
  425. .dialpad_box {
  426. /*background-color: #333333;*/
  427. background-color: rgba(0, 0, 0, 0.7);
  428. color: #FFFFFF;
  429. border-radius: 5px;
  430. padding: 10px;
  431. }
  432. strong {
  433. padding: 5px 5px;
  434. color: #FFFFFF;
  435. font-size: 30px;
  436. }
  437. sup {
  438. padding: 3px 3px;
  439. color: #FFFFFF;
  440. font-size: 10px;
  441. }
  442. .button_box {
  443. /*background-color: #333333;*/
  444. background-color: rgba(0, 0, 0, 0.7);
  445. color: #FFFFFF;
  446. border-radius: 5px;
  447. padding: 10px;
  448. font-size: 12px;
  449. }
  450. .caller_id {
  451. /*background-color: #333333;*/
  452. text-align: center;
  453. background-color: rgba(0, 0, 0, 0.7);
  454. color: #FFFFFF;
  455. border-radius: 5px;
  456. padding: 100px;
  457. font-size: 12px;
  458. margin-bottom: 50px;
  459. }
  460. </style>
  461. <?php
  462. //show the footer
  463. require_once "resources/footer.php";
  464. ?>