Browse Source

added webphone by default

master
i am da real crt yes 2 years ago
parent
commit
96f7216c1f
  1. 41
      app/webphone/app_config.php
  2. 83
      app/webphone/app_languages.php
  3. 15
      app/webphone/app_menu.php
  4. BIN
      app/webphone/img/bg.jpg
  5. BIN
      app/webphone/img/favicon.ico
  6. BIN
      app/webphone/img/screenshots/1.png
  7. BIN
      app/webphone/img/screenshots/2.png
  8. BIN
      app/webphone/img/screenshots/3.png
  9. 85
      app/webphone/phone/css/ctxSip.css
  10. 85
      app/webphone/phone/css/ctxSip.less
  11. 111
      app/webphone/phone/index.html
  12. 162
      app/webphone/phone/index.php
  13. 90
      app/webphone/phone/root.php
  14. 21553
      app/webphone/phone/scripts/SIP.js/sip.js
  15. 11860
      app/webphone/phone/scripts/SIP.js/sip.js.0.7.8
  16. 1
      app/webphone/phone/scripts/SIP.js/sip.min.js
  17. 40
      app/webphone/phone/scripts/SIP.js/sip.min.js.0.7.8
  18. 895
      app/webphone/phone/scripts/app.js
  19. 12
      app/webphone/phone/scripts/config-sample.js
  20. 12
      app/webphone/phone/scripts/config.js
  21. 7
      app/webphone/phone/scripts/moment.js/moment.min.js
  22. BIN
      app/webphone/phone/sounds/dtmf.mp3
  23. BIN
      app/webphone/phone/sounds/incoming.mp3
  24. BIN
      app/webphone/phone/sounds/outgoing.mp3
  25. 90
      app/webphone/root.php
  26. 134
      app/webphone/webphone.php

41
app/webphone/app_config.php

@ -0,0 +1,41 @@
<?php
//application details
$apps[$x]['name'] = "webphone";
$apps[$x]['uuid'] = "29ad51b0-6ab0-4d65-9394-629d1a34580b";
$apps[$x]['category'] = "Vendor";
$apps[$x]['subcategory'] = "";
$apps[$x]['version'] = "1.0";
$apps[$x]['license'] = "Mozilla Public License 1.1";
$apps[$x]['url'] = "http://www.fusionpbx.com";
$apps[$x]['description']['en-us'] = "Web Phone";
$apps[$x]['description']['en-gb'] = "";
$apps[$x]['description']['ar-eg'] = "";
$apps[$x]['description']['de-at'] = "";
$apps[$x]['description']['de-ch'] = "";
$apps[$x]['description']['de-de'] = "";
$apps[$x]['description']['es-cl'] = "";
$apps[$x]['description']['es-mx'] = "";
$apps[$x]['description']['fr-ca'] = "";
$apps[$x]['description']['fr-fr'] = "";
$apps[$x]['description']['he-il'] = "";
$apps[$x]['description']['it-it'] = "";
$apps[$x]['description']['nl-nl'] = "";
$apps[$x]['description']['pl-pl'] = "";
$apps[$x]['description']['pt-br'] = "";
$apps[$x]['description']['pt-pt'] = "";
$apps[$x]['description']['ro-ro'] = "";
$apps[$x]['description']['ru-ru'] = "";
$apps[$x]['description']['sv-se'] = "";
$apps[$x]['description']['uk-ua'] = "";
//permission details
$y=0;
$apps[$x]['permissions'][$y]['name'] = "webphone_view";
//$apps[$x]['permissions'][$y]['menu']['uuid'] = "000ed55e-7fbc-40b5-9631-506d0b6056b4";
$apps[$x]['permissions'][$y]['groups'][] = "superadmin";
$apps[$x]['permissions'][$y]['groups'][] = "admin";
$apps[$x]['permissions'][$y]['groups'][] = "user";
$apps[$x]['permissions'][$y]['groups'][] = "agent";
?>

83
app/webphone/app_languages.php

@ -0,0 +1,83 @@
<?php
$text['title-webphone']['en-us'] = "WebPhone";
$text['title-webphone']['ar-eg'] = "ة";
$text['title-webphone']['de-at'] = ""; //copied from de-de
$text['title-webphone']['de-ch'] = ""; //copied from de-de
$text['title-webphone']['de-de'] = "";
$text['title-webphone']['es-cl'] = "";
$text['title-webphone']['es-mx'] = ""; //copied from es-cl
$text['title-webphone']['fr-ca'] = ""; //copied from fr-fr
$text['title-webphone']['fr-fr'] = "";
$text['title-webphone']['he-il'] = "";
$text['title-webphone']['it-it'] = "";
$text['title-webphone']['nl-nl'] = "";
$text['title-webphone']['pl-pl'] = "";
$text['title-webphone']['pt-br'] = ""; //copied from pt-pt
$text['title-webphone']['pt-pt'] = "";
$text['title-webphone']['ro-ro'] = "";
$text['title-webphone']['ru-ru'] = "";
$text['title-webphone']['sv-se'] = "";
$text['title-webphone']['uk-ua'] = "";
$text['title-description-webphone']['en-us'] = "Webphone is a simple browser-based phone. Select an extension and click 'Launch'";
$text['title-description-webphone']['ar-eg'] = "ة";
$text['title-description-webphone']['de-at'] = ""; //copied from de-de
$text['title-description-webphone']['de-ch'] = ""; //copied from de-de
$text['title-description-webphone']['de-de'] = "";
$text['title-description-webphone']['es-cl'] = "";
$text['title-description-webphone']['es-mx'] = ""; //copied from es-cl
$text['title-description-webphone']['fr-ca'] = ""; //copied from fr-fr
$text['title-description-webphone']['fr-fr'] = "";
$text['title-description-webphone']['he-il'] = "";
$text['title-description-webphone']['it-it'] = "";
$text['title-description-webphone']['nl-nl'] = "";
$text['title-description-webphone']['pl-pl'] = "";
$text['title-description-webphone']['pt-br'] = ""; //copied from pt-pt
$text['title-description-webphone']['pt-pt'] = "";
$text['title-description-webphone']['ro-ro'] = "";
$text['title-description-webphone']['ru-ru'] = "";
$text['title-description-webphone']['sv-se'] = "";
$text['title-description-webphone']['uk-ua'] = "";
$text['label-select_extension']['en-us'] = "Select Extension";
$text['label-select_extension']['ar-eg'] = "ة";
$text['label-select_extension']['de-at'] = ""; //copied from de-de
$text['label-select_extension']['de-ch'] = ""; //copied from de-de
$text['label-select_extension']['de-de'] = "";
$text['label-select_extension']['es-cl'] = "";
$text['label-select_extension']['es-mx'] = ""; //copied from es-cl
$text['label-select_extension']['fr-ca'] = ""; //copied from fr-fr
$text['label-select_extension']['fr-fr'] = "";
$text['label-select_extension']['he-il'] = "";
$text['label-select_extension']['it-it'] = "";
$text['label-select_extension']['nl-nl'] = "";
$text['label-select_extension']['pl-pl'] = "";
$text['label-select_extension']['pt-br'] = ""; //copied from pt-pt
$text['label-select_extension']['pt-pt'] = "";
$text['label-select_extension']['ro-ro'] = "";
$text['label-select_extension']['ru-ru'] = "";
$text['label-select_extension']['sv-se'] = "";
$text['label-select_extension']['uk-ua'] = "";
$text['label-webphone_launch']['en-us'] = "Launch";
$text['label-webphone_launch']['ar-eg'] = "ة";
$text['label-webphone_launch']['de-at'] = ""; //copied from de-de
$text['label-webphone_launch']['de-ch'] = ""; //copied from de-de
$text['label-webphone_launch']['de-de'] = "";
$text['label-webphone_launch']['es-cl'] = "";
$text['label-webphone_launch']['es-mx'] = ""; //copied from es-cl
$text['label-webphone_launch']['fr-ca'] = ""; //copied from fr-fr
$text['label-webphone_launch']['fr-fr'] = "";
$text['label-webphone_launch']['he-il'] = "";
$text['label-webphone_launch']['it-it'] = "";
$text['label-webphone_launch']['nl-nl'] = "";
$text['label-webphone_launch']['pl-pl'] = "";
$text['label-webphone_launch']['pt-br'] = ""; //copied from pt-pt
$text['label-webphone_launch']['pt-pt'] = "";
$text['label-webphone_launch']['ro-ro'] = "";
$text['label-webphone_launch']['ru-ru'] = "";
$text['label-webphone_launch']['sv-se'] = "";
$text['label-webphone_launch']['uk-ua'] = "";
?>

15
app/webphone/app_menu.php

@ -0,0 +1,15 @@
<?php
$apps[$x]['menu'][0]['title']['en-us'] = "WebPhone";
$apps[$x]['menu'][0]['uuid'] = "b08f5f87-8a66-4c29-b1e6-eb0c374d58f2";
$apps[$x]['menu'][0]['parent_uuid'] = "";
$apps[$x]['menu'][0]['category'] = "internal";
$apps[$x]['menu'][0]['icon'] = "fa-phone";
$apps[$x]['menu'][0]['path'] = "/app/webphone/webphone.php";
$apps[$x]['menu'][0]['order'] = "28";
$apps[$x]['menu'][0]['groups'][] = "admin";
$apps[$x]['menu'][0]['groups'][] = "superadmin";
$apps[$x]['menu'][0]['groups'][] = "user";
$apps[$x]['menu'][0]['groups'][] = "agent";
?>

BIN
app/webphone/img/bg.jpg

After

Width: 1920  |  Height: 514  |  Size: 26 KiB

BIN
app/webphone/img/favicon.ico

After

Width: 16  |  Height: 16  |  Size: 438 B

BIN
app/webphone/img/screenshots/1.png

After

Width: 320  |  Height: 479  |  Size: 26 KiB

BIN
app/webphone/img/screenshots/2.png

After

Width: 321  |  Height: 478  |  Size: 31 KiB

BIN
app/webphone/img/screenshots/3.png

After

Width: 322  |  Height: 481  |  Size: 39 KiB

85
app/webphone/phone/css/ctxSip.css

@ -0,0 +1,85 @@
#sipClient {
background-color: #333;
font-size: 13px;
line-height: 1.42857143;
/* firefox 19+ */
/* ie */
}
#sipClient p {
margin: 0;
padding: 0 0 10px 0;
line-height: 18px;
}
#sipClient .sipStatus {
margin: 0 -15px 15px -15px;
padding: 5px 15px;
background-color: #111;
color: #999;
}
#sipClient #txtCallStatus {
color: #fff;
}
#sipClient #sip-dialpad {
width: 292px;
padding: 16px 20px;
}
#sipClient #sip-dialpad .col-xs-4 {
text-align: center;
}
#sipClient .digit {
height: 66px;
width: 66px;
margin: 0 8px 14px !important;
background-color: #f8f8f8;
font-weight: 300;
font-size: 24px;
border-radius: 100px;
line-height: 21px;
padding-top: 9px;
float: left;
}
#sipClient .digit span {
display: block;
color: #999;
font-size: 10px;
font-weight: normal;
}
#sipClient .sip-panel h3 {
margin-top: 22px;
}
#sipClient #sip-splash {
height: 371px;
}
#sipClient #sip-splash .fa {
margin-bottom: 15px;
}
#sipClient #sip-splash .fa-circle {
color: #5cb85c;
}
#sipClient #sip-log .panel-heading {
padding: 10px 8px;
}
#sipClient #sip-logitems {
height: 332px;
overflow: auto;
}
#sipClient #sldVolume {
width: 140px;
margin: 0 auto;
box-shadow: none;
}
#sipClient .sip-logitem {
padding: 4px;
}
#sipClient #numDisplay::-webkit-input-placeholder {
color: #bbb;
}
#sipClient #numDisplay::-moz-placeholder {
color: #bbb;
}
#sipClient #numDisplay::-ms-input-placeholder {
color: #bbb;
}
#sipClient #numDisplay::-moz-placeholder {
color: #bbb;
}

85
app/webphone/phone/css/ctxSip.less

@ -0,0 +1,85 @@
#sipClient {
background-color : #333;
font-size : 13px;
line-height : 1.42857143;
p {
margin : 0;
padding : 0 0 10px 0;
line-height : 18px;
}
.sipStatus {
margin : 0 -15px 15px -15px;
padding : 5px 15px;
background-color : #111;
color : #999;
}
#txtCallStatus { color : #fff; }
#sip-dialpad {
width : 292px;
padding : 16px 20px;
}
#sip-dialpad .col-xs-4 { text-align : center; }
.digit {
height : 66px;
width : 66px;
margin : 0 8px 14px !important;
background-color : #f8f8f8;
font-weight : 300;
font-size : 24px;
border-radius : 100px;
line-height : 21px;
padding-top : 9px;
float : left;
span {
display : block;
color : #999;
font-size : 10px;
font-weight : normal;
}
}
.sip-panel h3 { margin-top : 22px; }
#sip-splash {
height : 371px;
.fa {
margin-bottom : 15px;
}
.fa-circle {
color: #5cb85c;
}
}
#sip-log .panel-heading {
padding : 10px 8px;
}
#sip-logitems {
height : 332px;
overflow : auto;
}
#sldVolume {
width : 140px;
margin : 0 auto;
box-shadow : none;
}
.sip-logitem {
padding : 4px;
}
#numDisplay::-webkit-input-placeholder { color:#bbb; }
#numDisplay::-moz-placeholder { color:#bbb; }
#numDisplay::-ms-input-placeholder { color:#bbb; }
#numDisplay::-moz-placeholder { color:#bbb; }
}

111
app/webphone/phone/index.html

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>ctxSip</title>
<link rel="icon" type="image/gif" href="img/favicon.ico" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css">
<link href="css/ctxSip.css" rel="stylesheet" type="text/css" />
</head>
<body id="sipClient">
<div class="container-fluid">
<div class="clearfix sipStatus">
<div id="txtCallStatus" class="pull-right">&nbsp;</div>
<div id="txtRegStatus"></div>
</div>
<div class="form-group" id="phoneUI">
<div class="input-group">
<div class="input-group-btn">
<button class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown" title="Show Keypad">
<i class="fa fa-th"></i>
</button>
<div id="sip-dialpad" class="dropdown-menu">
<button type="button" class="btn btn-default digit" data-digit="1">1<span>&nbsp;</span></button>
<button type="button" class="btn btn-default digit" data-digit="2">2<span>ABC</span></button>
<button type="button" class="btn btn-default digit" data-digit="3">3<span>DEF</span></button>
<button type="button" class="btn btn-default digit" data-digit="4">4<span>GHI</span></button>
<button type="button" class="btn btn-default digit" data-digit="5">5<span>JKL</span></button>
<button type="button" class="btn btn-default digit" data-digit="6">6<span>MNO</span></button>
<button type="button" class="btn btn-default digit" data-digit="7">7<span>PQRS</span></button>
<button type="button" class="btn btn-default digit" data-digit="8">8<span>TUV</span></button>
<button type="button" class="btn btn-default digit" data-digit="9">9<span>WXYZ</span></button>
<button type="button" class="btn btn-default digit" data-digit="*">*<span>&nbsp;</span></button>
<button type="button" class="btn btn-default digit" data-digit="0">0<span>+</span></button>
<button type="button" class="btn btn-default digit" data-digit="#">#<span>&nbsp;</span></button>
<div class="clearfix">&nbsp;</div>
<button class="btn btn-success btn-block btnCall" title="Send">
<i class="fa fa-play"></i> Send
</button>
</div>
</div>
<input type="text" name="number" id="numDisplay" class="form-control text-center input-sm" value="" placeholder="Enter number..." autocomplete="off" />
<div class="input-group-btn input-group-btn-sm">
<button class="btn btn-sm btn-primary dropdown-toggle" id="btnVol" data-toggle="dropdown" title="Volume">
<i class="fa fa-fw fa-volume-up"></i>
</button>
<div class="dropdown-menu dropdown-menu-right">
<input type="range" min="0" max="100" value="100" step="1" id="sldVolume" />
</div>
</div>
</div>
</div>
<div class="well-sip">
<div id="sip-splash" class="text-muted text-center panel panel-default">
<div class="panel-body">
<h3 class="page-header">
<span class="fa-stack fa-2x">
<i class="fa fa-circle fa-stack-2x text-success"></i>
<i class="fa fa-phone fa-stack-1x fa-inverse"></i>
</span><br>
This is your phone.</h3>
<p class="lead">To make a call enter a number or SIP address in the box above.</p>
<small>Closing this window will cause calls to go to voicemail.</small>
</div>
</div>
<div id="sip-log" class="panel panel-default hide">
<div class="panel-heading">
<h4 class="text-muted panel-title">Recent Calls <span class="pull-right"><i class="fa fa-trash text-muted sipLogClear" title="Clear Log"></i></span></h4>
</div>
<div id="sip-logitems" class="list-group">
<p class="text-muted text-center">No recent calls from this browser.</p>
</div>
</div>
</div>
<div class="modal fade" id="mdlError" tabindex="-1" role="dialog" aria-hidden="true" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Sip Error</h4>
</div>
<div class="modal-body text-center text-danger">
<h3><i class="fa fa-3x fa-ban"></i></h3>
<p class="lead">Sip registration failed. No calls can be handled.</p>
</div>
</div>
</div>
</div>
</div>
<audio id="ringtone" src="sounds/incoming.mp3" loop></audio>
<audio id="ringbacktone" src="sounds/outgoing.mp3" loop></audio>
<audio id="dtmfTone" src="sounds/dtmf.mp3"></audio>
<audio id="audioRemote"></audio>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script type="text/javascript" src="scripts/moment.js/moment.min.js"></script>
<script type="text/javascript" src="scripts/SIP.js/sip.min.js"></script>
<script type="text/javascript" src="scripts/config.js"></script>
<script type="text/javascript" src="scripts/app.js"></script>
</body>
</html>

162
app/webphone/phone/index.php

@ -0,0 +1,162 @@
<?php
//includes
require_once "root.php";
require_once "resources/require.php";
require_once "resources/check_auth.php";
//check permissions
if (permission_exists('webphone_view')) {
//access granted
}
else {
echo "access denied";
exit;
}
//add multi-lingual support
$language = new text;
$text = $language->get();
if (is_uuid($_GET['id'])) {
$extension_uuid = $_GET['id'];
}
//get the user ID
$sql = "SELECT extension, password,effective_caller_id_name ";
$sql .= "FROM v_extensions ";
$sql .= "WHERE extension_uuid = '" . $extension_uuid . "' ";
$sql .= "AND v_extensions.domain_uuid = '" . $_SESSION["domain_uuid"] . "' LIMIT 1";
$prep_statement = $db->prepare($sql);
if ($prep_statement) {
$prep_statement->execute();
$row = $prep_statement->fetch(PDO::FETCH_ASSOC);
$user_extension = $row['extension'];
$user_password = $row['password'];
$effective_caller_id_name = $row['effective_caller_id_name'];
}
echo "<html lang='en'>\n";
echo "<head>\n";
echo " <meta charset='utf-8' />\n";
echo " <meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>\n";
echo " <title>ctxSip</title>\n";
echo " <link rel='icon' type='image/gif' href='img/favicon.ico' />\n";
echo " <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css'>\n";
echo " <link rel='stylesheet' href='//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css'>\n";
echo " <link href='css/ctxSip.css' rel='stylesheet' type='text/css' />\n";
echo "</head>\n";
echo "<body id='sipClient'>\n";
echo "<div class='container-fluid'>\n";
echo " <div class='clearfix sipStatus'>\n";
echo " <div id='txtCallStatus' class='pull-right'>&nbsp;</div>\n";
echo " <div id='txtRegStatus'></div>\n";
echo " </div>\n";
echo " <div class='form-group' id='phoneUI'>\n";
echo " <div class='input-group'>\n";
echo " <div class='input-group-btn'>\n";
echo " <button class='btn btn-sm btn-primary dropdown-toggle' data-toggle='dropdown' title='Show Keypad'>\n";
echo " <i class='fa fa-th'></i>\n";
echo " </button>\n";
echo " <div id='sip-dialpad' class='dropdown-menu'>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='1'>1<span>&nbsp;</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='2'>2<span>ABC</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='3'>3<span>DEF</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='4'>4<span>GHI</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='5'>5<span>JKL</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='6'>6<span>MNO</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='7'>7<span>PQRS</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='8'>8<span>TUV</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='9'>9<span>WXYZ</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='*'>*<span>&nbsp;</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='0'>0<span>+</span></button>\n";
echo " <button type='button' class='btn btn-default digit' data-digit='#'>#<span>&nbsp;</span></button>\n";
echo " <div class='clearfix'>&nbsp;</div>\n";
echo " <button class='btn btn-success btn-block btnCall' title='Send'>\n";
echo " <i class='fa fa-play'></i> Send\n";
echo " </button>\n";
echo " </div>\n";
echo " </div>\n";
echo " <input type='text' name='number' id='numDisplay' class='form-control text-center input-sm' value='' placeholder='Enter number...' autocomplete='off' />\n";
echo " <div class='input-group-btn input-group-btn-sm'>\n";
echo " <button class='btn btn-sm btn-primary dropdown-toggle' id='btnVol' data-toggle='dropdown' title='Volume'>\n";
echo " <i class='fa fa-fw fa-volume-up'></i>\n";
echo " </button>\n";
echo " <div class='dropdown-menu dropdown-menu-right'>\n";
echo " <input type='range' min='0' max='100' value='100' step='1' id='sldVolume' />\n";
echo " </div>\n";
echo " </div>\n";
echo " </div>\n";
echo " </div>\n";
echo " <div class=well-sip'>\n";
echo " <div id='sip-splash' class='text-muted text-center panel panel-default'>\n";
echo " <div class='panel-body'>\n";
echo " <h3 class='page-header'>\n";
echo " <span class='fa-stack fa-2x'>\n";
echo " <i class='fa fa-circle fa-stack-2x text-success'></i>\n";
echo " <i class='fa fa-phone fa-stack-1x fa-inverse'></i>\n";
echo " </span><br>\n";
echo " This is your phone.</h3>\n";
echo " <p class='lead'>To make a call enter a number in the box above.</p>\n";
echo " <small>Closing this window will cause calls to go to voicemail.</small>\n";
echo " </div>\n";
echo " </div>\n";
echo " <div id='sip-log' class='panel panel-default hide'>\n";
echo " <div class='panel-heading'>\n";
echo " <h4 class='text-muted panel-title'>Recent Calls <span class='pull-right'><i class='fa fa-trash text-muted sipLogClear' title='Clear Log'></i></span></h4>\n";
echo " </div>\n";
echo " <div id='sip-logitems' class='list-group'>\n";
echo " <p class='text-muted text-center'>No recent calls from this browser.</p>\n";
echo " </div>\n";
echo " </div>\n";
echo " </div>\n";
echo " <div class='modal fade' id='mdlError' tabindex='-1' role='dialog' aria-hidden='true' data-backdrop='static' data-keyboard='false'>\n";
echo " <div class='modal-dialog modal-sm'>\n";
echo " <div class='modal-content'>\n";
echo " <div class='modal-header'>\n";
echo " <h4 class='modal-title'>Sip Error</h4>\n";
echo " </div>\n";
echo " <div class='modal-body text-center text-danger'>\n";
echo " <h3><i class='fa fa-3x fa-ban'></i></h3>\n";
echo " <p class='lead'>Sip registration failed. No calls can be handled.</p>\n";
echo " </div>\n";
echo " </div>\n";
echo " </div>\n";
echo " </div>\n";
echo "</div>\n";
echo "<audio id='ringtone' src='sounds/incoming.mp3' loop></audio>\n";
echo "<audio id='ringbacktone' src='sounds/outgoing.mp3' loop></audio>\n";
echo "<audio id='dtmfTone' src='sounds/dtmf.mp3'></audio>\n";
echo "<audio id='audioRemote'></audio>\n";
echo "<script type='text/javascript' src='https://code.jquery.com/jquery-1.11.3.min.js'></script>\n";
echo "<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js'></script>\n";
echo "<script type='text/javascript' src='scripts/moment.js/moment.min.js'></script>\n";
//echo "<script type='text/javascript' src='scripts/SIP.js/sip.min.js'></script>\n";
echo "<script type='text/javascript' src='scripts/SIP.js/sip.js'></script>\n";
//echo "<script type='text/javascript' src='scripts/config.js'></script>\n";
echo "<script type='text/javascript'>\n";
echo "var user = {'User' : '" . $user_extension. "', ";
echo " 'Pass' : '".$user_password."', ";
echo " 'Realm' : '".$_SESSION["domain_name"]."', ";
echo " 'Display' : '".$effective_caller_id_name."', ";
echo " 'WSServer' : 'wss://".$_SESSION["domain_name"].":7443' ";
echo "};\n";
echo "</script>\n";
echo "<script type='text/javascript' src='scripts/app.js'></script>\n";
echo "</body>\n";
//</html>
?>

90
app/webphone/phone/root.php

@ -0,0 +1,90 @@
<?php
/*
FusionPBX
Version: MPL 1.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is FusionPBX
The Initial Developer of the Original Code is
Mark J Crane <markjcrane@fusionpbx.com>
Portions created by the Initial Developer are Copyright (C) 2008-2012
the Initial Developer. All Rights Reserved.
Contributor(s):
Mark J Crane <markjcrane@fusionpbx.com>
*/
// make sure the PATH_SEPARATOR is defined
umask(2);
if (!defined("PATH_SEPARATOR")) {
if (strpos($_ENV["OS"], "Win") !== false) {
define("PATH_SEPARATOR", ";");
} else {
define("PATH_SEPARATOR", ":");
}
}
if (!isset($output_format)) $output_format = (PHP_SAPI == 'cli') ? 'text' : 'html';
// make sure the document_root is set
$_SERVER["SCRIPT_FILENAME"] = str_replace("\\", '/', $_SERVER["SCRIPT_FILENAME"]);
if(PHP_SAPI == 'cli'){
chdir(pathinfo(realpath($_SERVER["PHP_SELF"]), PATHINFO_DIRNAME));
$script_full_path = str_replace("\\", '/', getcwd() . '/' . $_SERVER["SCRIPT_FILENAME"]);
$dirs = explode('/', pathinfo($script_full_path, PATHINFO_DIRNAME));
if (file_exists('/project_root.php')) {
$path = '/';
} else {
$i = 1;
$path = '';
while ($i < count($dirs)) {
$path .= '/' . $dirs[$i];
if (file_exists($path. '/project_root.php')) {
break;
}
$i++;
}
}
$_SERVER["DOCUMENT_ROOT"] = $path;
}else{
$_SERVER["DOCUMENT_ROOT"] = str_replace($_SERVER["PHP_SELF"], "", $_SERVER["SCRIPT_FILENAME"]);
}
$_SERVER["DOCUMENT_ROOT"] = realpath($_SERVER["DOCUMENT_ROOT"]);
// try to detect if a project path is being used
if (!defined('PROJECT_PATH')) {
if (is_dir($_SERVER["DOCUMENT_ROOT"]. '/fusionpbx')) {
define('PROJECT_PATH', '/fusionpbx');
} elseif (file_exists($_SERVER["DOCUMENT_ROOT"]. '/project_root.php')) {
define('PROJECT_PATH', '');
} else {
$dirs = explode('/', str_replace('\\', '/', pathinfo($_SERVER["PHP_SELF"], PATHINFO_DIRNAME)));
$i = 1;
$path = $_SERVER["DOCUMENT_ROOT"];
while ($i < count($dirs)) {
$path .= '/' . $dirs[$i];
if (file_exists($path. '/project_root.php')) {
break;
}
$i++;
}
if(!file_exists($path. '/project_root.php')){
die("Failed to locate the Project Root by searching for project_root.php please contact support for assistance");
}
$project_path = str_replace($_SERVER["DOCUMENT_ROOT"], "", $path);
define('PROJECT_PATH', $project_path);
}
$_SERVER["PROJECT_ROOT"] = realpath($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH);
set_include_path(get_include_path() . PATH_SEPARATOR . $_SERVER["PROJECT_ROOT"]);
}
?>

21553
app/webphone/phone/scripts/SIP.js/sip.js
File diff suppressed because it is too large
View File

11860
app/webphone/phone/scripts/SIP.js/sip.js.0.7.8
File diff suppressed because it is too large
View File

1
app/webphone/phone/scripts/SIP.js/sip.min.js
File diff suppressed because it is too large
View File

40
app/webphone/phone/scripts/SIP.js/sip.min.js.0.7.8
File diff suppressed because it is too large
View File

895
app/webphone/phone/scripts/app.js

@ -0,0 +1,895 @@
/* globals SIP,user,moment, Stopwatch */
var ctxSip;
$(document).ready(function() {
if (typeof(user) === 'undefined') {
user = JSON.parse(localStorage.getItem('SIPCreds'));
}
ctxSip = {
config : {
media : {
remote : {
video: document.getElementById('audioRemote'),
audio: document.getElementById('audioRemote')
}
},
peerConnectionOptions : {
rtcConfiguration : {
iceServers : [{urls:"stun:stun.l.google.com:19302"}]
}
},
password : user.Pass,
authorizationUser: user.User,
displayName : user.Display,
uri : user.User +'@'+user.Realm,
transportOptions: {
traceSip: true,
wsServers: user.WSServer,
},
registerExpires : 30,
ua: {}
},
ringtone : document.getElementById('ringtone'),
ringbacktone : document.getElementById('ringbacktone'),
dtmfTone : document.getElementById('dtmfTone'),
Sessions : [],
callTimers : {},
callActiveID : null,
callVolume : 1,
Stream : null,
/**
* Parses a SIP uri and returns a formatted US phone number.
*
* @param {string} phone number or uri to format
* @return {string} formatted number
*/
formatPhone : function(phone) {
var num;
if (phone.indexOf('@')) {
num = phone.split('@')[0];
} else {
num = phone;
}
num = num.toString().replace(/[^0-9]/g, '');
if (num.length === 10) {
return '(' + num.substr(0, 3) + ') ' + num.substr(3, 3) + '-' + num.substr(6,4);
} else if (num.length === 11) {
return '0' + num.substr(2);
} else {
return num;
}
},
// Sound methods
startRingTone : function() {
try { ctxSip.ringtone.play(); } catch (e) { }
},
stopRingTone : function() {
try { ctxSip.ringtone.pause(); } catch (e) { }
},
startRingbackTone : function() {
try { ctxSip.ringbacktone.play(); } catch (e) { }
},
stopRingbackTone : function() {
try { ctxSip.ringbacktone.pause(); } catch (e) { }
},
// Genereates a rendom string to ID a call
getUniqueID : function() {
return Math.random().toString(36).substr(2, 9);
},
newSession : function(newSess) {
newSess.displayName = newSess.remoteIdentity.displayName || newSess.remoteIdentity.uri.user;
newSess.ctxid = ctxSip.getUniqueID();
var status;
if (newSess.direction === 'incoming') {
status = "Incoming: "+ newSess.displayName;
ctxSip.startRingTone();
} else {
status = "Trying: "+ newSess.displayName;
ctxSip.startRingbackTone();
}
ctxSip.logCall(newSess, 'ringing');
ctxSip.setCallSessionStatus(status);
// EVENT CALLBACKS
var remoteVideo = document.getElementById('audioRemote');
var localVideo = document.getElementById('audioRemote');
newSess.on('trackAdded', function() {
// We need to check the peer connection to determine which track was added
var pc = newSess.sessionDescriptionHandler.peerConnection;
// Gets remote tracks
var remoteStream = new MediaStream();
pc.getReceivers().forEach(function(receiver) {
remoteStream.addTrack(receiver.track);
});
remoteVideo.srcObject = remoteStream;
remoteVideo.play();
});
newSess.on('progress',function(e) {
if (e.direction === 'outgoing') {
ctxSip.setCallSessionStatus('Calling...');
}
});
newSess.on('connecting',function(e) {
if (e.direction === 'outgoing') {
ctxSip.setCallSessionStatus('Connecting...');
}
});
newSess.on('accepted',function(e) {
// If there is another active call, hold it
if (ctxSip.callActiveID && ctxSip.callActiveID !== newSess.ctxid) {
ctxSip.phoneHoldButtonPressed(ctxSip.callActiveID);
}
ctxSip.stopRingbackTone();
ctxSip.stopRingTone();
ctxSip.setCallSessionStatus('Answered');
ctxSip.logCall(newSess, 'answered');
ctxSip.callActiveID = newSess.ctxid;
});
newSess.on('hold', function(e) {
ctxSip.callActiveID = null;
ctxSip.logCall(newSess, 'holding');
ctxSip.setCallSessionStatus("Holding");
});
newSess.on('unhold', function(e) {
ctxSip.logCall(newSess, 'resumed');
ctxSip.callActiveID = newSess.ctxid;
ctxSip.setCallSessionStatus("Answered");
});
newSess.on('muted', function(e) {
ctxSip.Sessions[newSess.ctxid].isMuted = true;
ctxSip.setCallSessionStatus("Muted");
});
newSess.on('unmuted', function(e) {
ctxSip.Sessions[newSess.ctxid].isMuted = false;
ctxSip.setCallSessionStatus("Answered");
});
newSess.on('cancel', function(e) {
ctxSip.stopRingTone();
ctxSip.stopRingbackTone();
ctxSip.setCallSessionStatus("Canceled");
if (this.direction === 'outgoing') {
ctxSip.callActiveID = null;
newSess = null;
ctxSip.logCall(this, 'ended');
}
});
newSess.on('bye', function(e) {
ctxSip.stopRingTone();
ctxSip.stopRingbackTone();
ctxSip.setCallSessionStatus("");
ctxSip.logCall(newSess, 'ended');
ctxSip.callActiveID = null;
newSess = null;
});
newSess.on('failed',function(e) {
ctxSip.stopRingTone();
ctxSip.stopRingbackTone();
ctxSip.setCallSessionStatus('Terminated');
});
newSess.on('rejected',function(e) {
ctxSip.stopRingTone();
ctxSip.stopRingbackTone();
ctxSip.setCallSessionStatus('Rejected');
ctxSip.callActiveID = null;
ctxSip.logCall(this, 'ended');
newSess = null;
});
ctxSip.Sessions[newSess.ctxid] = newSess;
},
// getUser media request refused or device was not present
getUserMediaFailure : function(e) {
window.console.error('getUserMedia failed:', e);
ctxSip.setError(true, 'Media Error.', 'You must allow access to your microphone. Check the address bar.', true);
},
getUserMediaSuccess : function(stream) {
ctxSip.Stream = stream;
},
/**
* sets the ui call status field
*
* @param {string} status
*/
setCallSessionStatus : function(status) {
$('#txtCallStatus').html(status);
},
/**
* sets the ui connection status field
*
* @param {string} status
*/
setStatus : function(status) {
$("#txtRegStatus").html('<i class="fa fa-signal"></i> '+status);
},
/**
* logs a call to localstorage
*
* @param {object} session
* @param {string} status Enum 'ringing', 'answered', 'ended', 'holding', 'resumed'
*/
logCall : function(session, status) {
var log = {
clid : session.displayName,
uri : session.remoteIdentity.uri.toString(),
id : session.ctxid,
time : new Date().getTime()
},
calllog = JSON.parse(localStorage.getItem('sipCalls'));
if (!calllog) { calllog = {}; }
if (!calllog.hasOwnProperty(session.ctxid)) {
calllog[log.id] = {
id : log.id,
clid : log.clid,
uri : log.uri,
start : log.time,
flow : session.direction
};
}
if (status === 'ended') {
calllog[log.id].stop = log.time;
}
if (status === 'ended' && calllog[log.id].status === 'ringing') {
calllog[log.id].status = 'missed';
} else {
calllog[log.id].status = status;
}
localStorage.setItem('sipCalls', JSON.stringify(calllog));
ctxSip.logShow();
},
/**
* adds a ui item to the call log
*
* @param {object} item log item
*/
logItem : function(item) {
var callActive = (item.status !== 'ended' && item.status !== 'missed'),
callLength = (item.status !== 'ended')? '<span id="'+item.id+'"></span>': moment.duration(item.stop - item.start).humanize(),
callClass = '',
callIcon,
i;
switch (item.status) {
case 'ringing' :
callClass = 'list-group-item-success';
callIcon = 'fa-bell';
break;
case 'missed' :
callClass = 'list-group-item-danger';
if (item.flow === "incoming") { callIcon = 'fa-chevron-left'; }
if (item.flow === "outgoing") { callIcon = 'fa-chevron-right'; }
break;
case 'holding' :
callClass = 'list-group-item-warning';
callIcon = 'fa-pause';
break;
case 'answered' :
case 'resumed' :
callClass = 'list-group-item-info';
callIcon = 'fa-phone-square';
break;
case 'ended' :
if (item.flow === "incoming") { callIcon = 'fa-chevron-left'; }
if (item.flow === "outgoing") { callIcon = 'fa-chevron-right'; }
break;
}
i = '<div class="list-group-item sip-logitem clearfix '+callClass+'" data-uri="'+item.uri+'" data-sessionid="'+item.id+'" title="Double Click to Call">';
i += '<div class="clearfix"><div class="pull-left">';
i += '<i class="fa fa-fw '+callIcon+' fa-fw"></i> <strong>'+ctxSip.formatPhone(item.uri)+'</strong><br><small>'+moment(item.start).format('MM/DD hh:mm:ss a')+'</small>';
i += '</div>';
i += '<div class="pull-left text-left"><em>'+item.clid+'</em><br>' + callLength+'</div></div>';
if (callActive) {
i += '<div class="btn-group btn-group-xs pull-right">';
if (item.status === 'ringing' && item.flow === 'incoming') {
i += '<button class="btn btn-xs btn-success btnCall" title="Call"><i class="fa fa-phone"></i></button>';
} else {
i += '<button class="btn btn-xs btn-primary btnHoldResume" title="Hold"><i class="fa fa-pause"></i></button>';
i += '<button class="btn btn-xs btn-info btnTransfer" title="Transfer"><i class="fa fa-random"></i></button>';
i += '<button class="btn btn-xs btn-warning btnMute" title="Mute"><i class="fa fa-fw fa-microphone"></i></button>';
}
i += '<button class="btn btn-xs btn-danger btnHangUp" title="Hangup"><i class="fa fa-stop"></i></button>';
i += '</div>';
}
i += '</div>';
$('#sip-logitems').append(i);
// Start call timer on answer
if (item.status === 'answered') {
var tEle = document.getElementById(item.id);
ctxSip.callTimers[item.id] = new Stopwatch(tEle);
ctxSip.callTimers[item.id].start();
}
if (callActive && item.status !== 'ringing') {
ctxSip.callTimers[item.id].start({startTime : item.start});
}
$('#sip-logitems').scrollTop(0);
},
/**
* updates the call log ui
*/
logShow : function() {
var calllog = JSON.parse(localStorage.getItem('sipCalls')),
x = [];
if (calllog !== null) {
$('#sip-splash').addClass('hide');
$('#sip-log').removeClass('hide');
// empty existing logs
$('#sip-logitems').empty();
// JS doesn't guarantee property order so
// create an array with the start time as
// the key and sort by that.
// Add start time to array
$.each(calllog, function(k,v) {
x.push(v);
});
// sort descending
x.sort(function(a, b) {
return b.start - a.start;
});
$.each(x, function(k, v) {
ctxSip.logItem(v);
});
} else {
$('#sip-splash').removeClass('hide');
$('#sip-log').addClass('hide');
}
},
/**
* removes log items from localstorage and updates the UI
*/
logClear : function() {
localStorage.removeItem('sipCalls');
ctxSip.logShow();
},
sipCall : function(target) {
try {
var s = ctxSip.phone.invite(target, {
media : {
remote : {
video: document.getElementById('audioRemote'),
audio: document.getElementById('audioRemote')
}
},
sessionDescriptionHandlerOptions : {
constraints : { audio : true, video : false },
rtcConfiguration : { RTCConstraints : { "optional": [{ 'DtlsSrtpKeyAgreement': 'true'} ]}, stream : ctxSip.Stream }
}
});
s.direction = 'outgoing';
ctxSip.newSession(s);
var remoteVideo = document.getElementById('audioRemote');
var localVideo = document.getElementById('audioRemote');
s.on('trackAdded', function() {
// We need to check the peer connection to determine which track was added
var pc = s.sessionDescriptionHandler.peerConnection;
// Gets remote tracks
var remoteStream = new MediaStream();
pc.getReceivers().forEach(function(receiver) {
remoteStream.addTrack(receiver.track);
});
remoteVideo.srcObject = remoteStream;
remoteVideo.play();
});
} catch(e) {
throw(e);
}
},
sipTransfer : function(sessionid) {
var s = ctxSip.Sessions[sessionid],
target = window.prompt('Enter destination number', '');
ctxSip.setCallSessionStatus('<i>Transfering the call...</i>');
s.refer(target);
},
sipHangUp : function(sessionid) {
var s = ctxSip.Sessions[sessionid];
// s.terminate();
if (!s) {
return;
} else if (s.startTime) {
s.bye();
} else if (s.reject) {
s.reject();
} else if (s.cancel) {
s.cancel();
}
},
sipSendDTMF : function(digit) {
try { ctxSip.dtmfTone.play(); } catch(e) { }
var a = ctxSip.callActiveID;
if (a) {
var s = ctxSip.Sessions[a];
s.dtmf(digit);
}
},
phoneCallButtonPressed : function(sessionid) {
var s = ctxSip.Sessions[sessionid],
target = $("#numDisplay").val();
if (!s) {
$("#numDisplay").val("");
ctxSip.sipCall(target);
} else if (s.accept && !s.startTime) {
s.accept({
media : {
remote : {
video: document.getElementById('audioRemote'),
audio: document.getElementById('audioRemote')
}
},
sessionDescriptionHandlerOptions : {
constraints : { audio : true, video : false },
rtcConfiguration : { RTCConstraints : { "optional": [{ 'DtlsSrtpKeyAgreement': 'true'} ]}, stream : ctxSip.Stream }
}
});
}
},
phoneMuteButtonPressed : function (sessionid) {
var s = ctxSip.Sessions[sessionid];
if (!s.isMuted) {
s.mute();
} else {
s.unmute();
}
},
phoneHoldButtonPressed : function(sessionid) {
var s = ctxSip.Sessions[sessionid];
var direction = s.sessionDescriptionHandler.getDirection();
if (direction === 'sendrecv') {
console.log('Call is not on hold');
s.hold();
} else {
console.log('Call is on hold');
s.unhold();
}
},
setError : function(err, title, msg, closable) {
// Show modal if err = true
if (err === true) {
$("#mdlError p").html(msg);
$("#mdlError").modal('show');
if (closable) {
var b = '<button type="button" class="close" data-dismiss="modal">&times;</button>';
$("#mdlError .modal-header").find('button').remove();
$("#mdlError .modal-header").prepend(b);
$("#mdlError .modal-title").html(title);
$("#mdlError").modal({ keyboard : true });
} else {
$("#mdlError .modal-header").find('button').remove();
$("#mdlError .modal-title").html(title);
$("#mdlError").modal({ keyboard : false });
}
// $('#numDisplay').prop('disabled', 'disabled');
} else {
$('#numDisplay').removeProp('disabled');
$("#mdlError").modal('hide');
}
},
/**
* Tests for a capable browser, return bool, and shows an
* error modal on fail.
*/
hasWebRTC : function() {
if (navigator.webkitGetUserMedia) {
return true;
} else if (navigator.mozGetUserMedia) {
return true;
} else if (navigator.getUserMedia) {
return true;
} else {
ctxSip.setError(true, 'Unsupported Browser.', 'Your browser does not support the features required for this phone.');
window.console.error("WebRTC support not found");
return false;
}
}
};
// Throw an error if the browser can't hack it.
if (!ctxSip.hasWebRTC()) {
return true;
}
ctxSip.phone = new SIP.UA(ctxSip.config);
ctxSip.phone.on('connected', function(e) {
ctxSip.setStatus("Connected");
ctxSip.setError(false)
});
ctxSip.phone.on('disconnected', function(e) {
ctxSip.setStatus("Disconnected");
// disable phone
ctxSip.setError(true, 'Websocket Disconnected.', 'An Error occurred connecting to the websocket.');
});
ctxSip.phone.on('registered', function(e) {
ctxSip.setError(false)
var closeEditorWarning = function() {
return 'If you close this window, you will not be able to make or receive calls from your browser.';
};
var closePhone = function() {
// stop the phone on unload
localStorage.removeItem('ctxPhone');
ctxSip.phone.stop();
};
window.onbeforeunload = closeEditorWarning;
window.onunload = closePhone;
// This key is set to prevent multiple windows.
localStorage.setItem('ctxPhone', 'true');
$("#mldError").modal('hide');
ctxSip.setStatus("Ready");
// Get the userMedia and cache the stream
// if (SIP.WebRTC.isSupported()) {
// SIP.WebRTC.getUserMedia({ audio : true, video : false }, ctxSip.getUserMediaSuccess, ctxSip.getUserMediaFailure);
// }
});
ctxSip.phone.on('registrationFailed', function(e) {
console.log(e)
ctxSip.setError(true, 'Registration Error.', 'An Error occurred registering your phone. Check your settings.');
ctxSip.setStatus("Error: Registration Failed");
});
ctxSip.phone.on('unregistered', function(e) {
ctxSip.setError(true, 'Registration Error.', 'An Error occurred registering your phone. Please wait while we try to connect it again.');
ctxSip.setStatus("Error: Registration Failed");
});
ctxSip.phone.on('invite',
function (incomingSession) {
var s = incomingSession;
s.direction = 'incoming';
ctxSip.newSession(s);
},);
// Auto-focus number input on backspace.
$('#sipClient').keydown(function(event) {
if (event.which === 8) {
$('#numDisplay').focus();
}
});
$('#numDisplay').keypress(function(e) {
// Enter pressed? so Dial.
if (e.which === 13) {
ctxSip.phoneCallButtonPressed();
}
});
$('#phoneIcon').click(function(eveny) {
// Enter pressed? so Dial.
event.preventDefault();
ctxSip.phoneCallButtonPressed();
});
$('.digit').click(function(event) {
event.preventDefault();
var num = $('#numDisplay').val(),
dig = $(this).data('digit');
$('#numDisplay').val(num+dig);
ctxSip.sipSendDTMF(dig);
return false;
});
$('#phoneUI .dropdown-menu').click(function(e) {
e.preventDefault();
});
$('#phoneUI').delegate('.btnCall', 'click', function(event) {
ctxSip.phoneCallButtonPressed();
// to close the dropdown
return true;
});
$('.sipLogClear').click(function(event) {
event.preventDefault();
ctxSip.logClear();
});
$('#sip-logitems').delegate('.sip-logitem .btnCall', 'click', function(event) {
var sessionid = $(this).closest('.sip-logitem').data('sessionid');
ctxSip.phoneCallButtonPressed(sessionid);
return false;
});
$('#sip-logitems').delegate('.sip-logitem .btnHoldResume', 'click', function(event) {
var sessionid = $(this).closest('.sip-logitem').data('sessionid');
ctxSip.phoneHoldButtonPressed(sessionid);
return false;
});
$('#sip-logitems').delegate('.sip-logitem .btnHangUp', 'click', function(event) {
var sessionid = $(this).closest('.sip-logitem').data('sessionid');
ctxSip.sipHangUp(sessionid);
return false;
});
$('#sip-logitems').delegate('.sip-logitem .btnTransfer', 'click', function(event) {
var sessionid = $(this).closest('.sip-logitem').data('sessionid');
ctxSip.sipTransfer(sessionid);
return false;
});
$('#sip-logitems').delegate('.sip-logitem .btnMute', 'click', function(event) {
var sessionid = $(this).closest('.sip-logitem').data('sessionid');
ctxSip.phoneMuteButtonPressed(sessionid);
return false;
});
$('#sip-logitems').delegate('.sip-logitem', 'dblclick', function(event) {
event.preventDefault();
var uri = $(this).data('uri');
$('#numDisplay').val(uri);
ctxSip.phoneCallButtonPressed();
});
$('#sldVolume').on('change', function() {
var v = $(this).val() / 100,
// player = $('audio').get()[0],
btn = $('#btnVol'),
icon = $('#btnVol').find('i'),
active = ctxSip.callActiveID;
// Set the object and media stream volumes
if (ctxSip.Sessions[active]) {
ctxSip.Sessions[active].player.volume = v;
ctxSip.callVolume = v;
}
// Set the others
$('audio').each(function() {
$(this).get()[0].volume = v;
});
if (v < 0.1) {
btn.removeClass(function (index, css) {
return (css.match (/(^|\s)btn\S+/g) || []).join(' ');
})
.addClass('btn btn-sm btn-danger');
icon.removeClass().addClass('fa fa-fw fa-volume-off');
} else if (v < 0.8) {
btn.removeClass(function (index, css) {
return (css.match (/(^|\s)btn\S+/g) || []).join(' ');
}).addClass('btn btn-sm btn-info');
icon.removeClass().addClass('fa fa-fw fa-volume-down');
} else {
btn.removeClass(function (index, css) {
return (css.match (/(^|\s)btn\S+/g) || []).join(' ');
}).addClass('btn btn-sm btn-primary');
icon.removeClass().addClass('fa fa-fw fa-volume-up');
}
return false;
});
// Hide the spalsh after 3 secs.
setTimeout(function() {
ctxSip.logShow();
}, 3000);
/**
* Stopwatch object used for call timers
*
* @param {dom element} elem
* @param {[object]} options
*/
var Stopwatch = function(elem, options) {
// private functions
function createTimer() {
return document.createElement("span");
}
var timer = createTimer(),
offset,
clock,
interval;
// default options
options = options || {};
options.delay = options.delay || 1000;
options.startTime = options.startTime || Date.now();
// append elements
elem.appendChild(timer);
function start() {
if (!interval) {
offset = options.startTime;
interval = setInterval(update, options.delay);
}
}
function stop() {
if (interval) {
clearInterval(interval);
interval = null;
}
}
function reset() {
clock = 0;
render();
}
function update() {
clock += delta();
render();
}
function render() {
timer.innerHTML = moment(clock).format('mm:ss');
}
function delta() {
var now = Date.now(),
d = now - offset;
offset = now;
return d;
}
// initialize
reset();
// public API
this.start = start; //function() { start; }
this.stop = stop; //function() { stop; }
};
});

12
app/webphone/phone/scripts/config-sample.js

@ -0,0 +1,12 @@
var user = {
// User Name
"User" : "sipuser",
// Password
"Pass" : "yourpassword",
// Auth Realm
"Realm" : "sip.sample.com",
// Display Name
"Display" : "Gob Bleuth",
// WebSocket URL
"WSServer" : "wss://wss.sample.com:8443"
};

12
app/webphone/phone/scripts/config.js

@ -0,0 +1,12 @@
var user = {
// User Name
"User" : "3000",
// Password
"Pass" : "dP.!saZ!vv",
// Auth Realm
"Realm" : "proxylab.encoretg.net",
// Display Name
"Display" : "Gob Bleuth",
// WebSocket URL
"WSServer" : "wss://proxylab.encoretg.net:7443"
};

7
app/webphone/phone/scripts/moment.js/moment.min.js
File diff suppressed because it is too large
View File

BIN
app/webphone/phone/sounds/dtmf.mp3

BIN
app/webphone/phone/sounds/incoming.mp3

BIN
app/webphone/phone/sounds/outgoing.mp3

90
app/webphone/root.php

@ -0,0 +1,90 @@
<?php
/*
FusionPBX
Version: MPL 1.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is FusionPBX
The Initial Developer of the Original Code is
Mark J Crane <markjcrane@fusionpbx.com>
Portions created by the Initial Developer are Copyright (C) 2008-2012
the Initial Developer. All Rights Reserved.
Contributor(s):
Mark J Crane <markjcrane@fusionpbx.com>
*/
// make sure the PATH_SEPARATOR is defined
umask(2);
if (!defined("PATH_SEPARATOR")) {
if (strpos($_ENV["OS"], "Win") !== false) {
define("PATH_SEPARATOR", ";");
} else {
define("PATH_SEPARATOR", ":");
}
}
if (!isset($output_format)) $output_format = (PHP_SAPI == 'cli') ? 'text' : 'html';
// make sure the document_root is set
$_SERVER["SCRIPT_FILENAME"] = str_replace("\\", '/', $_SERVER["SCRIPT_FILENAME"]);
if(PHP_SAPI == 'cli'){
chdir(pathinfo(realpath($_SERVER["PHP_SELF"]), PATHINFO_DIRNAME));
$script_full_path = str_replace("\\", '/', getcwd() . '/' . $_SERVER["SCRIPT_FILENAME"]);
$dirs = explode('/', pathinfo($script_full_path, PATHINFO_DIRNAME));
if (file_exists('/project_root.php')) {
$path = '/';
} else {
$i = 1;
$path = '';
while ($i < count($dirs)) {
$path .= '/' . $dirs[$i];
if (file_exists($path. '/project_root.php')) {
break;
}
$i++;
}
}
$_SERVER["DOCUMENT_ROOT"] = $path;
}else{
$_SERVER["DOCUMENT_ROOT"] = str_replace($_SERVER["PHP_SELF"], "", $_SERVER["SCRIPT_FILENAME"]);
}
$_SERVER["DOCUMENT_ROOT"] = realpath($_SERVER["DOCUMENT_ROOT"]);
// try to detect if a project path is being used
if (!defined('PROJECT_PATH')) {
if (is_dir($_SERVER["DOCUMENT_ROOT"]. '/fusionpbx')) {
define('PROJECT_PATH', '/fusionpbx');
} elseif (file_exists($_SERVER["DOCUMENT_ROOT"]. '/project_root.php')) {
define('PROJECT_PATH', '');
} else {
$dirs = explode('/', str_replace('\\', '/', pathinfo($_SERVER["PHP_SELF"], PATHINFO_DIRNAME)));
$i = 1;
$path = $_SERVER["DOCUMENT_ROOT"];
while ($i < count($dirs)) {
$path .= '/' . $dirs[$i];
if (file_exists($path. '/project_root.php')) {
break;
}
$i++;
}
if(!file_exists($path. '/project_root.php')){
die("Failed to locate the Project Root by searching for project_root.php please contact support for assistance");
}
$project_path = str_replace($_SERVER["DOCUMENT_ROOT"], "", $path);
define('PROJECT_PATH', $project_path);
}
$_SERVER["PROJECT_ROOT"] = realpath($_SERVER["DOCUMENT_ROOT"] . PROJECT_PATH);
set_include_path(get_include_path() . PATH_SEPARATOR . $_SERVER["PROJECT_ROOT"]);
}
?>

134
app/webphone/webphone.php

@ -0,0 +1,134 @@
<?php
/*
FusionPBX
Version: MPL 1.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is FusionPBX
The Initial Developer of the Original Code is
Mark J Crane <markjcrane@fusionpbx.com>
Portions created by the Initial Developer are Copyright (C) 2008-2016
the Initial Developer. All Rights Reserved.
Contributor(s):
KonradSC <konrd@yahoo.com>
Mark J Crane <markjcrane@fusionpbx.com>
*/
//includes
include "root.php";
require_once "resources/require.php";
require_once "resources/check_auth.php";
require_once "resources/paging.php";
//check permissions
if (permission_exists('webphone_view')) {
//access granted
}
else {
echo "access denied";
exit;
}
//create token
$object = new token;
$token = $object->create($_SERVER['PHP_SELF']);
//add multi-lingual support
$language = new text;
$text = $language->get();
//verify the id is as uuid then set as a variable
if (is_uuid($_GET['id'])) {
$extension_uuid = $_GET['id'];
}
//get the extension(s)
if (permission_exists('extension_edit')) {
//admin user
$sql = "select * from v_extensions ";
$sql .= "where domain_uuid = :domain_uuid ";
$sql .= "and enabled = 'true' ";
$sql .= "order by extension asc ";
}
else {
//normal user
$sql = "select e.* ";
$sql .= "from v_extensions as e, ";
$sql .= "v_extension_users as eu ";
$sql .= "where e.extension_uuid = eu.extension_uuid ";
$sql .= "and eu.user_uuid = :user_uuid ";
$sql .= "and e.domain_uuid = :domain_uuid ";
$sql .= "and e.enabled = 'true' ";
$sql .= "order by e.extension asc ";
$parameters['user_uuid'] = $_SESSION['user']['user_uuid'];
}
$parameters['domain_uuid'] = $_SESSION['domain_uuid'];
$database = new database;
$extensions = $database->select($sql, $parameters, 'all');
unset($sql, $parameters);
//include the header
$document['title'] = $text['title-webphone'];
require_once "resources/header.php";
echo "<form name='frm' id='frm' method='get'>\n";
echo "<div class='action_bar' id='action_bar'>\n";
echo " <div class='heading'><b>".$text['title-webphone']."</b></div>\n";
echo " <div class='actions'></div>\n";
echo " \n";
echo " <div style='clear: both;'></div>\n";
echo "</div>\n";
echo $text['title-description-webphone']."\n";
echo "<br /><br />\n";
echo "<div style='text-align: center; white-space: nowrap; margin: 10px 0 40px 0;'>";
echo $text['label-select_extension']."<br />\n";
echo "<select name='id' class='formfld' onchange='this.form.submit();'>\n";
echo " <option value='' >".$text['label-select']."...</option>\n";
if (is_array($extensions) && @sizeof($extensions) != 0) {
foreach ($extensions as $row) {
$selected = $row['extension_uuid'] == $extension_uuid ? "selected='selected'" : null;
echo " <option value='".escape($row['extension_uuid'])."' ".$selected.">".escape($row['extension'])." ".escape($row['number_alias'])." ".escape($row['description'])."</option>\n";
}
}
echo "</select>\n";
echo "<input type='hidden' name='".$token['name']."' value='".$token['hash']."'>\n";
echo "</form>\n";
//begin the content
if (strlen($extension_uuid) > 0 ) {
echo " <a href=\"phone\" id=\"launchPhone\">".$text['label-webphone_launch']."</a>\n";
}
echo " <script>\n";
echo " var url = 'phone/index.php?id=".escape($extension_uuid)."',\n";
echo " features = 'menubar=no,location=no,resizable=no,scrollbars=no,status=no,addressbar=no,width=320,height=480'\n";
echo " $('#launchPhone').on('click', function(event) { \n";
echo " event.preventDefault() \n";
// This is set when the phone is open and removed on close
echo " if (!localStorage.getItem('ctxPhone')) { \n";
echo " window.open(url, 'ctxPhone', features)\n";
echo " return false\n";
echo " } else { \n";
echo " window.alert('Phone already open.')\n";
echo " }\n";
echo " })\n";
echo " function updatevariable(data) { \n";
echo " value = data;\n";
echo " } \n";
echo " </script>\n";
echo "</div>\n";
//show the footer
require_once "resources/footer.php";
?>
Loading…
Cancel
Save