";
299 | echo "
\n";
300 |
301 |
302 | //show the content
303 | echo "
\n";
304 | echo "
Contacts".$text['header-contacts']." (".$num_rows.")
\n";
305 | echo "
\n";
306 | echo "\n";
314 | echo "
\n";
315 | echo "
\n";
316 | echo "
\n";
317 |
318 | echo $text['description-contacts']."\n";
319 | // echo "
\n";
320 | // echo "
\n";
321 |
322 | echo "
\n";
374 |
375 | //javascript
376 | echo "\n";
383 |
384 | echo "
\n";
385 | echo "\n";
386 | ?>
387 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Mozilla Public License Version 2.0
2 | ==================================
3 |
4 | 1. Definitions
5 | --------------
6 |
7 | 1.1. "Contributor"
8 | means each individual or legal entity that creates, contributes to
9 | the creation of, or owns Covered Software.
10 |
11 | 1.2. "Contributor Version"
12 | means the combination of the Contributions of others (if any) used
13 | by a Contributor and that particular Contributor's Contribution.
14 |
15 | 1.3. "Contribution"
16 | means Covered Software of a particular Contributor.
17 |
18 | 1.4. "Covered Software"
19 | means Source Code Form to which the initial Contributor has attached
20 | the notice in Exhibit A, the Executable Form of such Source Code
21 | Form, and Modifications of such Source Code Form, in each case
22 | including portions thereof.
23 |
24 | 1.5. "Incompatible With Secondary Licenses"
25 | means
26 |
27 | (a) that the initial Contributor has attached the notice described
28 | in Exhibit B to the Covered Software; or
29 |
30 | (b) that the Covered Software was made available under the terms of
31 | version 1.1 or earlier of the License, but not also under the
32 | terms of a Secondary License.
33 |
34 | 1.6. "Executable Form"
35 | means any form of the work other than Source Code Form.
36 |
37 | 1.7. "Larger Work"
38 | means a work that combines Covered Software with other material, in
39 | a separate file or files, that is not Covered Software.
40 |
41 | 1.8. "License"
42 | means this document.
43 |
44 | 1.9. "Licensable"
45 | means having the right to grant, to the maximum extent possible,
46 | whether at the time of the initial grant or subsequently, any and
47 | all of the rights conveyed by this License.
48 |
49 | 1.10. "Modifications"
50 | means any of the following:
51 |
52 | (a) any file in Source Code Form that results from an addition to,
53 | deletion from, or modification of the contents of Covered
54 | Software; or
55 |
56 | (b) any new file in Source Code Form that contains any Covered
57 | Software.
58 |
59 | 1.11. "Patent Claims" of a Contributor
60 | means any patent claim(s), including without limitation, method,
61 | process, and apparatus claims, in any patent Licensable by such
62 | Contributor that would be infringed, but for the grant of the
63 | License, by the making, using, selling, offering for sale, having
64 | made, import, or transfer of either its Contributions or its
65 | Contributor Version.
66 |
67 | 1.12. "Secondary License"
68 | means either the GNU General Public License, Version 2.0, the GNU
69 | Lesser General Public License, Version 2.1, the GNU Affero General
70 | Public License, Version 3.0, or any later versions of those
71 | licenses.
72 |
73 | 1.13. "Source Code Form"
74 | means the form of the work preferred for making modifications.
75 |
76 | 1.14. "You" (or "Your")
77 | means an individual or a legal entity exercising rights under this
78 | License. For legal entities, "You" includes any entity that
79 | controls, is controlled by, or is under common control with You. For
80 | purposes of this definition, "control" means (a) the power, direct
81 | or indirect, to cause the direction or management of such entity,
82 | whether by contract or otherwise, or (b) ownership of more than
83 | fifty percent (50%) of the outstanding shares or beneficial
84 | ownership of such entity.
85 |
86 | 2. License Grants and Conditions
87 | --------------------------------
88 |
89 | 2.1. Grants
90 |
91 | Each Contributor hereby grants You a world-wide, royalty-free,
92 | non-exclusive license:
93 |
94 | (a) under intellectual property rights (other than patent or trademark)
95 | Licensable by such Contributor to use, reproduce, make available,
96 | modify, display, perform, distribute, and otherwise exploit its
97 | Contributions, either on an unmodified basis, with Modifications, or
98 | as part of a Larger Work; and
99 |
100 | (b) under Patent Claims of such Contributor to make, use, sell, offer
101 | for sale, have made, import, and otherwise transfer either its
102 | Contributions or its Contributor Version.
103 |
104 | 2.2. Effective Date
105 |
106 | The licenses granted in Section 2.1 with respect to any Contribution
107 | become effective for each Contribution on the date the Contributor first
108 | distributes such Contribution.
109 |
110 | 2.3. Limitations on Grant Scope
111 |
112 | The licenses granted in this Section 2 are the only rights granted under
113 | this License. No additional rights or licenses will be implied from the
114 | distribution or licensing of Covered Software under this License.
115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
116 | Contributor:
117 |
118 | (a) for any code that a Contributor has removed from Covered Software;
119 | or
120 |
121 | (b) for infringements caused by: (i) Your and any other third party's
122 | modifications of Covered Software, or (ii) the combination of its
123 | Contributions with other software (except as part of its Contributor
124 | Version); or
125 |
126 | (c) under Patent Claims infringed by Covered Software in the absence of
127 | its Contributions.
128 |
129 | This License does not grant any rights in the trademarks, service marks,
130 | or logos of any Contributor (except as may be necessary to comply with
131 | the notice requirements in Section 3.4).
132 |
133 | 2.4. Subsequent Licenses
134 |
135 | No Contributor makes additional grants as a result of Your choice to
136 | distribute the Covered Software under a subsequent version of this
137 | License (see Section 10.2) or under the terms of a Secondary License (if
138 | permitted under the terms of Section 3.3).
139 |
140 | 2.5. Representation
141 |
142 | Each Contributor represents that the Contributor believes its
143 | Contributions are its original creation(s) or it has sufficient rights
144 | to grant the rights to its Contributions conveyed by this License.
145 |
146 | 2.6. Fair Use
147 |
148 | This License is not intended to limit any rights You have under
149 | applicable copyright doctrines of fair use, fair dealing, or other
150 | equivalents.
151 |
152 | 2.7. Conditions
153 |
154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155 | in Section 2.1.
156 |
157 | 3. Responsibilities
158 | -------------------
159 |
160 | 3.1. Distribution of Source Form
161 |
162 | All distribution of Covered Software in Source Code Form, including any
163 | Modifications that You create or to which You contribute, must be under
164 | the terms of this License. You must inform recipients that the Source
165 | Code Form of the Covered Software is governed by the terms of this
166 | License, and how they can obtain a copy of this License. You may not
167 | attempt to alter or restrict the recipients' rights in the Source Code
168 | Form.
169 |
170 | 3.2. Distribution of Executable Form
171 |
172 | If You distribute Covered Software in Executable Form then:
173 |
174 | (a) such Covered Software must also be made available in Source Code
175 | Form, as described in Section 3.1, and You must inform recipients of
176 | the Executable Form how they can obtain a copy of such Source Code
177 | Form by reasonable means in a timely manner, at a charge no more
178 | than the cost of distribution to the recipient; and
179 |
180 | (b) You may distribute such Executable Form under the terms of this
181 | License, or sublicense it under different terms, provided that the
182 | license for the Executable Form does not attempt to limit or alter
183 | the recipients' rights in the Source Code Form under this License.
184 |
185 | 3.3. Distribution of a Larger Work
186 |
187 | You may create and distribute a Larger Work under terms of Your choice,
188 | provided that You also comply with the requirements of this License for
189 | the Covered Software. If the Larger Work is a combination of Covered
190 | Software with a work governed by one or more Secondary Licenses, and the
191 | Covered Software is not Incompatible With Secondary Licenses, this
192 | License permits You to additionally distribute such Covered Software
193 | under the terms of such Secondary License(s), so that the recipient of
194 | the Larger Work may, at their option, further distribute the Covered
195 | Software under the terms of either this License or such Secondary
196 | License(s).
197 |
198 | 3.4. Notices
199 |
200 | You may not remove or alter the substance of any license notices
201 | (including copyright notices, patent notices, disclaimers of warranty,
202 | or limitations of liability) contained within the Source Code Form of
203 | the Covered Software, except that You may alter any license notices to
204 | the extent required to remedy known factual inaccuracies.
205 |
206 | 3.5. Application of Additional Terms
207 |
208 | You may choose to offer, and to charge a fee for, warranty, support,
209 | indemnity or liability obligations to one or more recipients of Covered
210 | Software. However, You may do so only on Your own behalf, and not on
211 | behalf of any Contributor. You must make it absolutely clear that any
212 | such warranty, support, indemnity, or liability obligation is offered by
213 | You alone, and You hereby agree to indemnify every Contributor for any
214 | liability incurred by such Contributor as a result of warranty, support,
215 | indemnity or liability terms You offer. You may include additional
216 | disclaimers of warranty and limitations of liability specific to any
217 | jurisdiction.
218 |
219 | 4. Inability to Comply Due to Statute or Regulation
220 | ---------------------------------------------------
221 |
222 | If it is impossible for You to comply with any of the terms of this
223 | License with respect to some or all of the Covered Software due to
224 | statute, judicial order, or regulation then You must: (a) comply with
225 | the terms of this License to the maximum extent possible; and (b)
226 | describe the limitations and the code they affect. Such description must
227 | be placed in a text file included with all distributions of the Covered
228 | Software under this License. Except to the extent prohibited by statute
229 | or regulation, such description must be sufficiently detailed for a
230 | recipient of ordinary skill to be able to understand it.
231 |
232 | 5. Termination
233 | --------------
234 |
235 | 5.1. The rights granted under this License will terminate automatically
236 | if You fail to comply with any of its terms. However, if You become
237 | compliant, then the rights granted under this License from a particular
238 | Contributor are reinstated (a) provisionally, unless and until such
239 | Contributor explicitly and finally terminates Your grants, and (b) on an
240 | ongoing basis, if such Contributor fails to notify You of the
241 | non-compliance by some reasonable means prior to 60 days after You have
242 | come back into compliance. Moreover, Your grants from a particular
243 | Contributor are reinstated on an ongoing basis if such Contributor
244 | notifies You of the non-compliance by some reasonable means, this is the
245 | first time You have received notice of non-compliance with this License
246 | from such Contributor, and You become compliant prior to 30 days after
247 | Your receipt of the notice.
248 |
249 | 5.2. If You initiate litigation against any entity by asserting a patent
250 | infringement claim (excluding declaratory judgment actions,
251 | counter-claims, and cross-claims) alleging that a Contributor Version
252 | directly or indirectly infringes any patent, then the rights granted to
253 | You by any and all Contributors for the Covered Software under Section
254 | 2.1 of this License shall terminate.
255 |
256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257 | end user license agreements (excluding distributors and resellers) which
258 | have been validly granted by You or Your distributors under this License
259 | prior to termination shall survive termination.
260 |
261 | ************************************************************************
262 | * *
263 | * 6. Disclaimer of Warranty *
264 | * ------------------------- *
265 | * *
266 | * Covered Software is provided under this License on an "as is" *
267 | * basis, without warranty of any kind, either expressed, implied, or *
268 | * statutory, including, without limitation, warranties that the *
269 | * Covered Software is free of defects, merchantable, fit for a *
270 | * particular purpose or non-infringing. The entire risk as to the *
271 | * quality and performance of the Covered Software is with You. *
272 | * Should any Covered Software prove defective in any respect, You *
273 | * (not any Contributor) assume the cost of any necessary servicing, *
274 | * repair, or correction. This disclaimer of warranty constitutes an *
275 | * essential part of this License. No use of any Covered Software is *
276 | * authorized under this License except under this disclaimer. *
277 | * *
278 | ************************************************************************
279 |
280 | ************************************************************************
281 | * *
282 | * 7. Limitation of Liability *
283 | * -------------------------- *
284 | * *
285 | * Under no circumstances and under no legal theory, whether tort *
286 | * (including negligence), contract, or otherwise, shall any *
287 | * Contributor, or anyone who distributes Covered Software as *
288 | * permitted above, be liable to You for any direct, indirect, *
289 | * special, incidental, or consequential damages of any character *
290 | * including, without limitation, damages for lost profits, loss of *
291 | * goodwill, work stoppage, computer failure or malfunction, or any *
292 | * and all other commercial damages or losses, even if such party *
293 | * shall have been informed of the possibility of such damages. This *
294 | * limitation of liability shall not apply to liability for death or *
295 | * personal injury resulting from such party's negligence to the *
296 | * extent applicable law prohibits such limitation. Some *
297 | * jurisdictions do not allow the exclusion or limitation of *
298 | * incidental or consequential damages, so this exclusion and *
299 | * limitation may not apply to You. *
300 | * *
301 | ************************************************************************
302 |
303 | 8. Litigation
304 | -------------
305 |
306 | Any litigation relating to this License may be brought only in the
307 | courts of a jurisdiction where the defendant maintains its principal
308 | place of business and such litigation shall be governed by laws of that
309 | jurisdiction, without reference to its conflict-of-law provisions.
310 | Nothing in this Section shall prevent a party's ability to bring
311 | cross-claims or counter-claims.
312 |
313 | 9. Miscellaneous
314 | ----------------
315 |
316 | This License represents the complete agreement concerning the subject
317 | matter hereof. If any provision of this License is held to be
318 | unenforceable, such provision shall be reformed only to the extent
319 | necessary to make it enforceable. Any law or regulation which provides
320 | that the language of a contract shall be construed against the drafter
321 | shall not be used to construe this License against a Contributor.
322 |
323 | 10. Versions of the License
324 | ---------------------------
325 |
326 | 10.1. New Versions
327 |
328 | Mozilla Foundation is the license steward. Except as provided in Section
329 | 10.3, no one other than the license steward has the right to modify or
330 | publish new versions of this License. Each version will be given a
331 | distinguishing version number.
332 |
333 | 10.2. Effect of New Versions
334 |
335 | You may distribute the Covered Software under the terms of the version
336 | of the License under which You originally received the Covered Software,
337 | or under the terms of any subsequent version published by the license
338 | steward.
339 |
340 | 10.3. Modified Versions
341 |
342 | If you create software not governed by this License, and you want to
343 | create a new license for such software, you may create and use a
344 | modified version of this License if you rename the license and remove
345 | any references to the name of the license steward (except to note that
346 | such modified license differs from this License).
347 |
348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
349 | Licenses
350 |
351 | If You choose to distribute Source Code Form that is Incompatible With
352 | Secondary Licenses under the terms of this version of the License, the
353 | notice described in Exhibit B of this License must be attached.
354 |
355 | Exhibit A - Source Code Form License Notice
356 | -------------------------------------------
357 |
358 | This Source Code Form is subject to the terms of the Mozilla Public
359 | License, v. 2.0. If a copy of the MPL was not distributed with this
360 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
361 |
362 | If it is not possible or desirable to put the notice in a particular
363 | file, then You may include the notice in a location (such as a LICENSE
364 | file in a relevant directory) where a recipient would be likely to look
365 | for such a notice.
366 |
367 | You may add additional accurate notices of copyright ownership.
368 |
369 | Exhibit B - "Incompatible With Secondary Licenses" Notice
370 | ---------------------------------------------------------
371 |
372 | This Source Code Form is "Incompatible With Secondary Licenses", as
373 | defined by the Mozilla Public License, v. 2.0.
374 |
--------------------------------------------------------------------------------
/saraphone.js:
--------------------------------------------------------------------------------
1 | /*
2 | SaraPhone
3 | Version: MPL 1.1
4 |
5 | The contents of this file are subject to 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 |
10 | Software distributed under the License is distributed on an "AS IS" basis,
11 | WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 | for the specific language governing rights and limitations under the
13 | License.
14 |
15 | The Original Code is SaraPhone
16 |
17 | The Initial Developer of the Original Code is
18 | Giovanni Maruzzelli
19 | Portions created by the Initial Developer are Copyright (C) 2020
20 | the Initial Developer. All Rights Reserved.
21 |
22 | SaraPhone gets its name from Giovanni's wife, Sara.
23 |
24 | Author(s):
25 | Giovanni Maruzzelli
26 | Danilo Volpinari
27 | Luca Mularoni
28 | */
29 |
30 | 'use strict';
31 |
32 | var cur_call = null;
33 | var ua;
34 | var which_server;
35 | var isAndroid = false;
36 | var isIOS = false;
37 | var isOnMute = false;
38 | var isOnHold = false;
39 | var clicklogin = "no";
40 | var isRecording = false;
41 | var isDnd = false;
42 | var isNoRing = false;
43 | var isAutoAnswer = false;
44 | var isRegistered = false;
45 | var vmail_subscription = false;
46 | var presence_array = new Array();
47 | var incomingsession = null;
48 | var audioElement = document.createElement('audio');
49 | var callTimer;
50 | var oldext = false;
51 | var gotopanel = false;
52 | var isIncomingCall = false;
53 | var isOutboundCall = false;
54 |
55 | var dtmf_options = {
56 | 'duration': 100,
57 | 'interToneGap': 100
58 | };
59 |
60 | //http://jsfiddle.net/55Kfu/1506/
61 | //https://stackoverflow.com/posts/13194087/revisions
62 | var beep = (function() {
63 | var ctxClass = window.audioContext || window.AudioContext || window.AudioContext || window.webkitAudioContext
64 | var ctx = new ctxClass();
65 | return function(duration, type, finishedCallback) {
66 |
67 | duration = +duration;
68 |
69 | // Only 0-4 are valid types.
70 | type = (type % 5) || 0;
71 |
72 | if (typeof finishedCallback != "function") {
73 | finishedCallback = function() {};
74 | }
75 |
76 | var osc = ctx.createOscillator();
77 |
78 | //osc.type = type;
79 | osc.type = "sine";
80 |
81 | osc.connect(ctx.destination);
82 | if (osc.noteOn) osc.noteOn(0); // old browsers
83 | if (osc.start) osc.start(); // new browsers
84 |
85 | setTimeout(function() {
86 | if (osc.noteOff) osc.noteOff(0); // old browsers
87 | if (osc.stop) osc.stop(); // new browsers
88 | finishedCallback();
89 | }, duration);
90 |
91 | };
92 | })();
93 |
94 | function tempAlert(msg,duration)
95 | {
96 | var el = document.createElement("div");
97 | el.setAttribute("style","position:absolute;top:1%;left:1%;background-color:red;foreground-color:black;");
98 | el.innerHTML = msg;
99 | setTimeout(function(){
100 | el.parentNode.removeChild(el);
101 | location.reload(true);
102 | },duration);
103 | document.body.appendChild(el);
104 | console.error("TEMPALERT");
105 | }
106 |
107 |
108 |
109 | function onCancelled() {
110 | audioElement.pause();
111 | console.log('cancelled');
112 | $("#isIncomingcall").hide();
113 | $("#isNotIncomingcall").show();
114 | incomingsession = null;
115 | var span = document.getElementById('calling');
116 | $("#calling_input").val("");
117 | span.innerText = "...";
118 | }
119 |
120 | function onTerminated() {
121 | audioElement.pause();
122 | console.log('Onterminated');
123 | $("#signin").hide();
124 | $("#dial").show();
125 | $("#incall").hide();
126 | $("#ext").val("");
127 | if (cur_call) {
128 | cur_call.terminate();
129 | cur_call = null;
130 | resetOptionsTimer();
131 | }
132 | isOnMute = false;
133 |
134 | incomingsession = null;
135 |
136 | var span = document.getElementById('calling');
137 | $("#calling_input").val("");
138 | span.innerText = "...";
139 | }
140 |
141 | function onTerminated2() {
142 | console.log('Onterminated2');
143 | cur_call = null;
144 | incomingsession = null;
145 | }
146 |
147 | function onAccepted() {
148 | audioElement.pause();
149 |
150 | $("#signin").hide();
151 | $("#dial").hide();
152 | $("#incall").show();
153 |
154 | isOnMute = false;
155 | $("#mutebtn").removeClass('btn-danger').addClass('btn-warning');
156 |
157 | }
158 |
159 | $("#asknotificationpermission").click(function() {
160 | if (isIOS) {
161 | //do nothing
162 | } else {
163 | // Let's check if the browser supports notifications
164 | if (!("Notification" in window)) {
165 | alert("This browser does not support desktop notification");
166 | }
167 |
168 | // Otherwise, we need to ask the user for permission
169 | // Note, Chrome does not implement the permission static property
170 | // So we have to check for NOT 'denied' instead of 'default'
171 | else if (Notification.permission !== 'denied') {
172 | Notification.requestPermission(function(permission) {
173 |
174 | // Whatever the user answers, we make sure we store the information
175 | if (!('permission' in Notification)) {
176 | Notification.permission = permission;
177 | }
178 |
179 | // If the user is okay, let's create a notification
180 | if (permission === "granted") {
181 | console.log("Notification Permission Granted!");
182 | var notification = new Notification("Notification Permission Granted!");
183 | $("#asknotificationpermission").hide();
184 | }
185 | });
186 | } else {
187 | alert(`Permission is ${Notification.permission}`);
188 | }
189 |
190 | }
191 | });
192 |
193 |
194 | function notifyMe(msg) {
195 | if (isIOS) {
196 | //do nothing
197 | } else {
198 | if (Notification.permission === "granted") {
199 | console.log(msg);
200 | let img = 'img/notification.png';
201 | let notification = new Notification('WebPhone', {
202 | body: msg,
203 | icon: img
204 | });
205 | notification.onclick = function() {
206 | parent.focus();
207 | window.focus();
208 | this.close();
209 | };
210 | notification.onclose = function() {
211 | parent.focus();
212 | window.focus();
213 | this.close();
214 | };
215 | notification.onerror = function() {
216 | parent.focus();
217 | window.focus();
218 | this.close();
219 | };
220 | }
221 | }
222 | }
223 |
224 |
225 | function onRegistered() {
226 | if (isIOS) {
227 | //do nothing
228 | } else {
229 | if (Notification.permission === "granted") {
230 | $("#asknotificationpermission").hide();
231 | }
232 | }
233 |
234 | $("#signin").hide();
235 | $("#dial").show();
236 | $("#incall").hide();
237 | $("#ext").val("");
238 | var span = document.getElementById('calling');
239 | $("#calling_input").val("");
240 | span.innerText = "...";
241 |
242 | var span = document.getElementById('whoami');
243 | var txt = document.createTextNode($("#login").val());
244 | span.innerText = txt.textContent + " (" + $("#yourname").val() + ")";
245 |
246 | isRegistered = true;
247 |
248 |
249 | var countpres = 1;
250 |
251 | while (countpres < 61) {
252 | if ($("#pres" + countpres).val()) {
253 | presence_array[countpres] = ua.subscribe($("#pres" + countpres).val(), 'presence', {
254 | expires: 120
255 | });
256 |
257 | const mycountpres = countpres;
258 | presence_array[countpres].on('notify', function(notification) {
259 | //console.log(notification.request.body);
260 |
261 | var presence = notification.request.body.match(/(.*)<\/dm:note>/i);
262 | if (presence) {
263 | var ispresent = presence[1];
264 |
265 | if (ispresent.match(/unregistered/i)) {
266 | $("#pres" + mycountpres + "btn").removeClass('btn-success btn-warning btn-default btn-danger').addClass('btn-danger');
267 | } else {
268 | if (ispresent.match(/available/i) || ispresent.match(/closed/i)) {
269 | $("#pres" + mycountpres + "btn").removeClass('btn-success btn-warning btn-default btn-danger').addClass('btn-success');
270 |
271 | } else {
272 | $("#pres" + mycountpres + "btn").removeClass('btn-success btn-warning btn-default btn-danger').addClass('btn-warning');
273 | }
274 | }
275 |
276 | var span = document.getElementById('ispresent' + mycountpres);
277 | $("#pres" + mycountpres + "_label").val($("#pres" + mycountpres + "_label").val().substr(0, 10));
278 | if (ispresent.match(/available/i) || ispresent.match(/closed/i)) {
279 | span.innerText = $("#pres" + mycountpres + "_label").val();
280 | } else {
281 | span.innerText = $("#pres" + mycountpres + "_label").val() + ": " + ispresent;
282 | }
283 | }
284 |
285 | });
286 |
287 |
288 |
289 | $("#pres" + mycountpres + "btn").click(function() {
290 | $("#ext").val($("#pres" + mycountpres).val());
291 | oldext=$("#ext").val();
292 | docall();
293 | });
294 |
295 |
296 |
297 | } else {
298 |
299 | $("#pres" + countpres + "btn").remove();
300 |
301 | }
302 | countpres++;
303 | }
304 |
305 | $("#webphone_blf").show();
306 |
307 |
308 | // Once subscribed, receive notifications and handle
309 | vmail_subscription = ua.subscribe($("#login").val() + '@' + $("#domain").val(), 'message-summary', {
310 | extraHeaders: ['Accept: application/simple-message-summary'],
311 | expires: 120
312 | });
313 | vmail_subscription.on('notify', handleNotify);
314 |
315 | if (isAndroid || isIOS) {
316 | $("#calling_input").hide();
317 | }
318 | }
319 |
320 | $("#checkvmailbtn").click(function() {
321 | $("#extstarbtn").click();
322 | $("#ext9btn").click();
323 | $("#ext8btn").click();
324 | $("#callbtn").click();
325 | });
326 |
327 | $("#gotopanel1").click(function() {
328 | gotopanel = true;
329 | console.error("GOTOPANEL1");
330 | window.location.assign('/');
331 | });
332 |
333 | $("#gotopanel2").click(function() {
334 | gotopanel = true;
335 | console.error("GOTOPANEL2");
336 | window.location.assign('/');
337 | });
338 |
339 | $("#gotopanel3").click(function() {
340 | gotopanel = true;
341 | console.error("GOTOPANEL3");
342 | window.location.assign('/');
343 | });
344 |
345 | function handleNotify(r) {
346 | //console.log(r.request.method);
347 | //console.log(r.request.body);
348 |
349 | var newMessages = 0;
350 | var oldMessages = 0;
351 | var span = document.getElementById('vmailcount');
352 | var gotmsg = r.request.body.match(/voice-message:\s*(\d+)\/(\d+)/i);
353 | if (gotmsg) {
354 | newMessages = parseInt(gotmsg[1]);
355 | oldMessages = parseInt(gotmsg[2]);
356 | if (newMessages) {
357 | $("#checkvmailbtn").removeClass('btn-info').addClass('btn-warning');
358 |
359 | } else {
360 | $("#checkvmailbtn").removeClass('btn-warning').addClass('btn-info');
361 |
362 | }
363 | span.innerText = newMessages + "/" + oldMessages;
364 | }
365 |
366 |
367 | }
368 |
369 |
370 | $("#anscallbtn").click(function() {
371 | audioElement.pause();
372 | incomingsession.accept({
373 | media: {
374 | constraints: {
375 | audio: {
376 | deviceId: {
377 | ideal: $("#selectmic").val()
378 | }
379 | },
380 | video: false
381 | },
382 | render: {
383 | remote: document.getElementById('audio')
384 | }
385 | }
386 | });
387 | console.log('answered');
388 |
389 | $("#isIncomingcall").hide();
390 | $("#isNotIncomingcall").show();
391 | cur_call = incomingsession;
392 | var span = document.getElementById('speakingwith');
393 | var txt = document.createTextNode(cur_call.remoteIdentity.displayName.toString());
394 | span.innerText = txt.textContent + " (" + cur_call.remoteIdentity.uri.user.toString() + ")";
395 |
396 | cur_call.on('accepted', onAccepted.bind(cur_call));
397 | cur_call.once('bye', onTerminated.bind(cur_call));
398 | cur_call.once('failed', onTerminated.bind(cur_call));
399 | cur_call.once('cancel', onTerminated.bind(cur_call));
400 | cur_call.once('terminated', onTerminated2.bind(cur_call));
401 | });
402 |
403 |
404 | $("#rejcallbtn").click(function() {
405 | audioElement.pause();
406 | incomingsession.reject({
407 | statusCode: '486',
408 | reasonPhrase: 'Busy Here 1'
409 | });
410 | console.log('rejected');
411 | $("#isIncomingcall").hide();
412 | $("#isNotIncomingcall").show();
413 | var span = document.getElementById('calling');
414 | $("#calling_input").val("");
415 | span.innerText = "...";
416 | incomingsession = null;
417 | });
418 |
419 |
420 |
421 | function handleInvite(s) {
422 | if (cur_call) {
423 | s.reject({
424 | statusCode: '486',
425 | reasonPhrase: 'Busy Here 2'
426 | });
427 | }
428 | if (isDnd) {
429 | s.reject({
430 | statusCode: '486',
431 | reasonPhrase: 'Busy Here 3'
432 | });
433 | } else {
434 | if (!cur_call) {
435 | var span = document.getElementById('calling');
436 | var txt = "---";
437 | isIncomingCall = true;
438 | isOutboundCall = false;
439 | if(s.remoteIdentity.displayName && s.remoteIdentity.displayName.toString()) {
440 | txt = document.createTextNode(s.remoteIdentity.displayName.toString());
441 | }
442 | span.innerText = "CALL FROM: " + txt.textContent + " (" + s.remoteIdentity.uri.user.toString() + ")";
443 | incomingsession = s;
444 | $("#isIncomingcall").show();
445 | $("#isNotIncomingcall").hide();
446 | incomingsession.once('cancel', onCancelled.bind(incomingsession));
447 |
448 | if (isIOS) {
449 | //do nothing
450 | } else {
451 | notifyMe("CALL FROM: " + txt.textContent + " (" + s.remoteIdentity.uri.user.toString() + ")");
452 | }
453 |
454 | if (isNoRing == false) {
455 | audioElement.currentTime = 0;
456 | audioElement.play();
457 | }
458 | if (isAutoAnswer == true) {
459 | $("#anscallbtn").trigger("click");
460 | }
461 | }
462 | }
463 | }
464 |
465 |
466 | function docall() {
467 |
468 | if (cur_call) {
469 | cur_call.terminate();
470 | cur_call = null;
471 | resetOptionsTimer();
472 | }
473 |
474 | isIncomingCall = false;
475 | isOutboundCall = true;
476 |
477 | cur_call = ua.invite($("#ext").val(), {
478 | media: {
479 | constraints: {
480 | audio: {
481 | deviceId: {
482 | ideal: $("#selectmic").val()
483 | }
484 | },
485 | video: false
486 | },
487 | render: {
488 | remote: document.getElementById('audio')
489 | }
490 | }
491 | });
492 |
493 | cur_call.on('accepted', onAccepted.bind(cur_call));
494 | cur_call.once('failed', function(response, cause) {
495 | if (cause != "null") {
496 | console.log(cause);
497 | } else {
498 | cause = "N/A";
499 | }
500 | var span = document.getElementById('calling');
501 | onTerminated(cur_call);
502 | var txt = document.createTextNode(response.status_code + ": " + cause);
503 | span.innerText = txt.textContent;
504 | })
505 |
506 | cur_call.once('bye', function(request) {
507 | if (request.headers.Reason && !(request.headers.Reason["0"].raw.toString().match(/cause=16/)) && !(request.headers.Reason["0"].raw.toString().match(/cause=31/))) {
508 | console.log(request);
509 | var span = document.getElementById('calling');
510 | onTerminated(cur_call);
511 | var regex = /.*text="(.*)".*/;
512 | var txt = document.createTextNode(request.headers.Reason["0"].raw.toString().replace(regex, "$1"));
513 | span.innerText = txt.textContent;
514 | } else {
515 | onTerminated(cur_call);
516 | }
517 | })
518 | cur_call.once('cancel', onTerminated.bind(cur_call));
519 |
520 | var span = document.getElementById('speakingwith');
521 | var txt = document.createTextNode($("#ext").val());
522 | span.innerText = txt.textContent;
523 | }
524 |
525 |
526 | $("#dialctrlbtn").click(function() {
527 | var x = document.getElementById('dialadv1');
528 | if (x.style.display === 'none') {
529 | x.style.display = 'block';
530 | } else {
531 | x.style.display = 'none';
532 | }
533 | x = document.getElementById('dialadv2');
534 | if (x.style.display === 'none') {
535 | x.style.display = 'block';
536 | } else {
537 | x.style.display = 'none';
538 | }
539 |
540 |
541 | });
542 |
543 | $("#signinctrlbtn").click(function() {
544 | var x = document.getElementById('signinadv1');
545 | if (x.style.display === 'none') {
546 | x.style.display = 'block';
547 | } else {
548 | x.style.display = 'none';
549 | }
550 | });
551 |
552 |
553 |
554 | $("#callbtn").click(function() {
555 | if ($("#ext").val()) {
556 | var regex1 = /#/g;
557 | var new_ext = $("#ext").val().replace(regex1, "_");
558 | $("#ext").val(new_ext);
559 | oldext=$("#ext").val();
560 | docall();
561 | }
562 | });
563 |
564 | $("#delcallbtn").click(function() {
565 | $("#ext").val("");
566 | $("#calling_input").val("");
567 | var span = document.getElementById('calling');
568 | span.innerText = "...";
569 |
570 | $("#hangupbtn").trigger("click");
571 | });
572 |
573 |
574 | $("#hangupbtn").click(function() {
575 | if (cur_call) {
576 | cur_call.terminate();
577 | cur_call = null;
578 | resetOptionsTimer();
579 | }
580 | $("#br").show();
581 | $("#ext").show();
582 | $("#calling_input").val("");
583 | var span = document.getElementById('calling');
584 | span.innerText = "...";
585 | });
586 |
587 |
588 | $("#loginbtn").click(function() {
589 | init();
590 | });
591 |
592 | $("#xferbtn").click(function() {
593 | if(isOutboundCall==true){
594 | cur_call.dtmf("*499", dtmf_options);
595 | }else{
596 | cur_call.dtmf("*599", dtmf_options);
597 | }
598 | });
599 |
600 | $("#attxbtn").click(function() {
601 | if(isOutboundCall==true){
602 | cur_call.dtmf("*699", dtmf_options);
603 | }else{
604 | cur_call.dtmf("*799", dtmf_options);
605 | }
606 | });
607 |
608 | $("#mutebtn").click(function() {
609 | if (isOnMute) {
610 | cur_call.unmute();
611 | isOnMute = false;
612 | $(this).removeClass('btn-danger').addClass('btn-warning');
613 | } else {
614 | cur_call.mute();
615 | isOnMute = true;
616 |
617 | $(this).removeClass('btn-warning').addClass('btn-danger');
618 | }
619 | });
620 |
621 | $("#holdbtn").click(function() {
622 | if (isOnHold==false){
623 | isOnHold = true;
624 | if(isOutboundCall==true){
625 | cur_call.dtmf("*299", dtmf_options);
626 | }else{
627 | cur_call.dtmf("*399", dtmf_options);
628 | }
629 | $("#unholdbtn").show();
630 | console.error("HOLD begins");
631 | }
632 | });
633 |
634 | $("#unholdbtn").click(function() {
635 | if (isOnHold == true){
636 | isOnHold = false;
637 | $("#extstarbtn").click();
638 | $("#ext6btn").click();
639 | $("#ext5btn").click();
640 | $("#ext5btn").click();
641 | $("#callbtn").click();
642 | $("#unholdbtn").hide();
643 | console.error("HOLD ends");
644 | }
645 | });
646 |
647 | $("#redialbtn").click(function() {
648 | audioElement.pause();
649 | $("#ext").val(oldext);
650 | $("#callbtn").click();
651 | });
652 |
653 | $("#callbackbtn").click(function() {
654 | audioElement.pause();
655 | $("#extstarbtn").click();
656 | $("#ext6btn").click();
657 | $("#ext9btn").click();
658 | $("#callbtn").click();
659 | });
660 |
661 | $("#recordcallbtn").click(function() {
662 | if (isRecording) {
663 | cur_call.dtmf("*");
664 | cur_call.dtmf("2");
665 | isRecording = false;
666 | $(this).removeClass('btn-danger').addClass('btn-warning');
667 | } else {
668 | cur_call.dtmf("*");
669 | cur_call.dtmf("2");
670 | isRecording = true;
671 |
672 | $(this).removeClass('btn-warning').addClass('btn-danger');
673 | }
674 | });
675 |
676 | $("#dndbtn").click(function() {
677 | if (isDnd) {
678 | isDnd = false;
679 | $(this).removeClass('btn-danger').addClass('btn-warning');
680 | } else {
681 | isDnd = true;
682 | $(this).removeClass('btn-warning').addClass('btn-danger');
683 | }
684 | });
685 |
686 | $("#ringbtn").click(function() {
687 | if (isNoRing) {
688 | isNoRing = false;
689 | $(this).removeClass('btn-danger').addClass('btn-warning');
690 | } else {
691 | isNoRing = true;
692 | $(this).removeClass('btn-warning').addClass('btn-danger');
693 | }
694 | });
695 |
696 | $("#autoanswerbtn").click(function() {
697 | if (isAutoAnswer) {
698 | isAutoAnswer = false;
699 | $(this).removeClass('btn-danger').addClass('btn-warning');
700 | } else {
701 | isAutoAnswer = true;
702 | $(this).removeClass('btn-warning').addClass('btn-danger');
703 | }
704 | });
705 |
706 |
707 |
708 | $("#ext1btn").click(function() {
709 | $("#ext").val($("#ext").val() + "1");
710 | var span = document.getElementById('calling');
711 | var txt = document.createTextNode($("#ext").val());
712 | span.innerText = "DIALING: " + txt.textContent;
713 | });
714 |
715 | $("#ext2btn").click(function() {
716 | $("#ext").val($("#ext").val() + "2");
717 | var span = document.getElementById('calling');
718 | var txt = document.createTextNode($("#ext").val());
719 | span.innerText = "DIALING: " + txt.textContent;
720 | });
721 |
722 | $("#ext3btn").click(function() {
723 | $("#ext").val($("#ext").val() + "3");
724 | var span = document.getElementById('calling');
725 | var txt = document.createTextNode($("#ext").val());
726 | span.innerText = "DIALING: " + txt.textContent;
727 | });
728 |
729 | $("#ext4btn").click(function() {
730 | $("#ext").val($("#ext").val() + "4");
731 | var span = document.getElementById('calling');
732 | var txt = document.createTextNode($("#ext").val());
733 | span.innerText = "DIALING: " + txt.textContent;
734 | });
735 |
736 | $("#ext5btn").click(function() {
737 | $("#ext").val($("#ext").val() + "5");
738 | var span = document.getElementById('calling');
739 | var txt = document.createTextNode($("#ext").val());
740 | span.innerText = "DIALING: " + txt.textContent;
741 | });
742 |
743 | $("#ext6btn").click(function() {
744 | $("#ext").val($("#ext").val() + "6");
745 | var span = document.getElementById('calling');
746 | var txt = document.createTextNode($("#ext").val());
747 | span.innerText = "DIALING: " + txt.textContent;
748 | });
749 |
750 | $("#ext7btn").click(function() {
751 | $("#ext").val($("#ext").val() + "7");
752 | var span = document.getElementById('calling');
753 | var txt = document.createTextNode($("#ext").val());
754 | span.innerText = "DIALING: " + txt.textContent;
755 | });
756 |
757 | $("#ext8btn").click(function() {
758 | $("#ext").val($("#ext").val() + "8");
759 | var span = document.getElementById('calling');
760 | var txt = document.createTextNode($("#ext").val());
761 | span.innerText = "DIALING: " + txt.textContent;
762 | });
763 |
764 | $("#ext9btn").click(function() {
765 | $("#ext").val($("#ext").val() + "9");
766 | var span = document.getElementById('calling');
767 | var txt = document.createTextNode($("#ext").val());
768 | span.innerText = "DIALING: " + txt.textContent;
769 | });
770 |
771 | $("#ext0btn").click(function() {
772 | $("#ext").val($("#ext").val() + "0");
773 | var span = document.getElementById('calling');
774 | var txt = document.createTextNode($("#ext").val());
775 | span.innerText = "DIALING: " + txt.textContent;
776 | });
777 |
778 | $("#extstarbtn").click(function() {
779 | $("#ext").val($("#ext").val() + "*");
780 | var span = document.getElementById('calling');
781 | var txt = document.createTextNode($("#ext").val());
782 | span.innerText = "DIALING: " + txt.textContent;
783 | });
784 |
785 | $("#extpoundbtn").click(function() {
786 | $("#ext").val($("#ext").val() + "#");
787 | var span = document.getElementById('calling');
788 | var txt = document.createTextNode($("#ext").val());
789 | span.innerText = "DIALING: " + txt.textContent;
790 | });
791 |
792 | $("#dtmf1btn").click(function() {
793 | cur_call.dtmf("1", dtmf_options);
794 | });
795 |
796 | $("#dtmf2btn").click(function() {
797 | cur_call.dtmf("2", dtmf_options);
798 | });
799 |
800 | $("#dtmf3btn").click(function() {
801 | cur_call.dtmf("3", dtmf_options);
802 | });
803 |
804 | $("#dtmf4btn").click(function() {
805 | cur_call.dtmf("4", dtmf_options);
806 | });
807 |
808 | $("#dtmf5btn").click(function() {
809 | cur_call.dtmf("5", dtmf_options);
810 | });
811 |
812 | $("#dtmf6btn").click(function() {
813 | cur_call.dtmf("6", dtmf_options);
814 | });
815 |
816 | $("#dtmf7btn").click(function() {
817 | cur_call.dtmf("7", dtmf_options);
818 | });
819 |
820 | $("#dtmf8btn").click(function() {
821 | cur_call.dtmf("8", dtmf_options);
822 | });
823 |
824 | $("#dtmf9btn").click(function() {
825 | cur_call.dtmf("9", dtmf_options);
826 | });
827 |
828 | $("#dtmf0btn").click(function() {
829 | cur_call.dtmf("0", dtmf_options);
830 | });
831 |
832 | $("#dtmfstarbtn").click(function() {
833 | cur_call.dtmf("*", dtmf_options);
834 | });
835 |
836 | $("#dtmfpoundbtn").click(function() {
837 | cur_call.dtmf("#", dtmf_options);
838 | });
839 |
840 |
841 | function resetOptionsTimer() {
842 | /*
843 | window.clearTimeout(callTimer);
844 |
845 | callTimer = window.setTimeout(function() {
846 | console.error("NETWORK DISCONNECT, NO OPTIONS SINCE 25000 msec");
847 | beep(1000, 2);
848 | if (cur_call) {
849 | alert("NETWORK DISCONNECT, CLICK OK TO PROCEED");
850 | }
851 | $("#hangupbtn").trigger("click");
852 | if (gotopanel == false){
853 | location.reload();
854 | }
855 | }, 25000);
856 | */
857 | }
858 |
859 | function init() {
860 |
861 | var nameDomain;
862 | var nameProxy;
863 | var uri;
864 | var password;
865 | var login;
866 | var yourname;
867 | var wssport;
868 |
869 | cur_call = null;
870 | resetOptionsTimer();
871 | yourname = $("#yourname").val();
872 | nameDomain = $("#domain").val();
873 | nameProxy = $("#proxy").val();
874 | wssport = $("#port").val();
875 | which_server = "wss://" + nameProxy + ":" + wssport;
876 |
877 | if (yourname === "") {
878 | yourname = $("#login").val();
879 | }
880 |
881 | login = $("#login").val();
882 | password = $("#passwd").val();
883 |
884 | uri = login + "@" + nameDomain;
885 |
886 | //console.error("uri: " + uri);
887 |
888 | ua = new SIP.UA({
889 | wsServers: which_server,
890 | uri: uri,
891 | password: password,
892 | userAgentString: 'SIP.js/0.7.8 SaraPhone 04',
893 | traceSip: true,
894 | displayName: yourname,
895 | iceCheckingTimeout: 1000,
896 | registerExpires: 120,
897 | allowLegacyNotifications: true,
898 | hackWssInTransport: true,
899 | wsServerMaxReconnection: 5000,
900 | wsServerReconnectionTimeout: 1,
901 | connectionRecoveryMaxInterval: 3,
902 | connectionRecoveryMinInterval: 2,
903 | log: {
904 | level: 2,
905 | connector: function(level, category, label, content) {
906 | var str = content;
907 | var patt2 = new RegExp("WebSocket abrupt disconnection");
908 | var res2 = patt2.exec(str);
909 | /*
910 | var patt = new RegExp("OPTIONS sip");
911 | var res = patt.exec(str);
912 |
913 | if (res) {
914 | resetOptionsTimer();
915 | }
916 | */
917 | if (res2) {
918 | if (gotopanel == false){
919 | console.error('WebSocket ABRUPT DISCONNECTION');
920 | tempAlert("- WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - WebSocket ABRUPT DISCONNECTION - ",10000);
921 | }
922 | }
923 | },
924 | }
925 | });
926 |
927 | ua.on('notify', handleNotify);
928 | ua.on('invite', handleInvite);
929 | ua.on('disconnected', function() {
930 | console.error('DISCONNECTED');
931 | //alert("DO YOU HAVE AUTHORIZED SSL CERTS FOR PORT 7443 ???? - READ THE README! :) - NETWORK DISCONNECT, CLICK OK TO PROCEED");
932 | if (gotopanel == false){
933 | tempAlert("- NETWORK DISCONNECTED - NETWORK DISCONNECTED - NETWORK DISCONNECTED - NETWORK DISCONNECTED - DO YOU HAVE WSS PORT OPEN ON FIREWALL? DO YOU HAVE AUTHORIZED SSL CERTS? AND YOUR WSS CERTS, ARE AUTHORIZED? - READ THE README! :) - NETWORK DISCONNECTED - NETWORK DISCONNECTED - NETWORK DISCONNECTED - NETWORK DISCONNECTED - ",60000);
934 | }
935 | });
936 |
937 | $("#isIncomingcall").hide();
938 |
939 | $(document).keyup(function(event) {
940 | if (event.keyCode == 13 && !event.shiftKey) {
941 | if (isRegistered) {
942 | if (cur_call) {} else {
943 | $("#callbtn").trigger("click");
944 | }
945 | }
946 | }
947 | });
948 |
949 | $(document).keypress(function(event) {
950 | var key = String.fromCharCode(event.keyCode || event.charCode);
951 | var i = parseInt(key);
952 | var tag = event.target.tagName.toLowerCase();
953 | if (isRegistered) {
954 | if (cur_call) {
955 | if (key === "#" || key === "*" || key === "0" || (i > 0 && i <= 9)) {
956 | cur_call.dtmf(key, dtmf_options);
957 | }
958 | } else {
959 |
960 | if (key === "#" || key === "*" || key === "0" || (i > 0 && i <= 9)) {
961 |
962 | if (key === "0") $("#ext0btn").click();
963 | if (key === "1") $("#ext1btn").click();
964 | if (key === "2") $("#ext2btn").click();
965 | if (key === "3") $("#ext3btn").click();
966 | if (key === "4") $("#ext4btn").click();
967 | if (key === "5") $("#ext5btn").click();
968 | if (key === "6") $("#ext6btn").click();
969 | if (key === "7") $("#ext7btn").click();
970 | if (key === "8") $("#ext8btn").click();
971 | if (key === "9") $("#ext9btn").click();
972 | if (key === "*") $("#extstarbtn").click();
973 | if (key === "#") $("#extpoundbtn").click();
974 | }
975 | }
976 | }
977 | });
978 |
979 | ua.once('registered', onRegistered.bind(cur_call));
980 | ua.on('unregistered', function() {
981 | console.error('UNREGISTERED');
982 | if (gotopanel == false){
983 | tempAlert("- UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - UNREGISTERED - ",3000);
984 | }
985 | });
986 | }
987 |
988 | $("#calling_input").keyup(function(event) {
989 | if (event.keyCode == 13 && !event.shiftKey) {
990 | $("#ext").val($("#calling_input").val());
991 | $("#callbtn").trigger("click");
992 | }
993 | });
994 |
995 | /*
996 | window.onbeforeunload = function(e) {
997 | e = e || window.event;
998 |
999 | console.log("closing window");
1000 |
1001 | // For IE and Firefox prior to version 4
1002 | if (e) {
1003 | e.returnValue = "Sure?";
1004 | }
1005 |
1006 | return "Sure?";
1007 | };
1008 | */
1009 |
1010 | $(window).load(function() {
1011 | cur_call = null;
1012 | resetOptionsTimer();
1013 | isAndroid = (navigator.userAgent.toLowerCase().indexOf('android') > -1);
1014 | isIOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
1015 |
1016 | console.log("The doctor is in");
1017 | console.log("Is something troubling you?");
1018 |
1019 |
1020 | var url_string = window.location.href; //window.location.href
1021 | var url = new URL(url_string);
1022 |
1023 | clicklogin = url.searchParams.get("clicklogin");
1024 |
1025 | $("#signin").hide();
1026 | $("#dial").hide();
1027 | $("#incall").hide();
1028 |
1029 | $("#controls").hide();
1030 | $("#dialadv1").hide();
1031 | $("#dialadv2").hide();
1032 | $("#unholdbtn").hide();
1033 |
1034 | $("#yourname").keyup(function(event) {
1035 | if (event.keyCode == 13 && !event.shiftKey) {
1036 | $("#loginbtn").trigger("click");
1037 | }
1038 | });
1039 |
1040 | $("#passwd").keyup(function(event) {
1041 | if (event.keyCode == 13 && !event.shiftKey) {
1042 | $("#loginbtn").trigger("click");
1043 | }
1044 | });
1045 | $("#login").keyup(function(event) {
1046 | if (event.keyCode == 13 && !event.shiftKey) {
1047 | $("#loginbtn").trigger("click");
1048 | }
1049 | });
1050 | $("#ext").keyup(function(event) {
1051 | if (event.keyCode == 13 && !event.shiftKey) {
1052 | $("#callbtn").trigger("click");
1053 | }
1054 | });
1055 |
1056 |
1057 | // Safari requires the user to grant device access before providing
1058 | // all necessary device info, so do that first.
1059 | var constraints = {
1060 | audio: true,
1061 | video: false,
1062 | };
1063 | navigator.mediaDevices.getUserMedia(constraints);
1064 |
1065 | navigator.mediaDevices.enumerateDevices()
1066 | .then(function(devices) {
1067 | var i = 1;
1068 | var div = document.querySelector("#listmic"),
1069 | frag = document.createDocumentFragment(),
1070 | selectmic = document.createElement("select");
1071 |
1072 | while (div.firstChild) {
1073 | div.removeChild(div.firstChild);
1074 | }
1075 | i = 1;
1076 | selectmic.id = "selectmic";
1077 | selectmic.style = "background-color: black;";
1078 |
1079 | devices.forEach(function(device) {
1080 |
1081 |
1082 | if (device.kind === 'audioinput') {
1083 |
1084 | selectmic.options.add(new Option('Microphone: ' + (device.label ? device.label : (i)), device.deviceId));
1085 | i++;
1086 |
1087 | }
1088 | });
1089 |
1090 | frag.appendChild(selectmic);
1091 |
1092 | div.appendChild(frag);
1093 |
1094 | })
1095 | .catch(function(err) {
1096 | console.log(err.name + ": " + err.message);
1097 | });
1098 |
1099 | document.getElementById("hideAll").style.display = "none";
1100 | $("#signin").show();
1101 | $("#signinadv1").hide();
1102 |
1103 | $("#webphone_blf").hide();
1104 |
1105 | if (clicklogin === "yes") {
1106 | $("#loginbtn").trigger("click");
1107 | }
1108 | });
1109 |
1110 |
1111 | $(document).ready(function() {
1112 | audioElement.setAttribute('src', 'mp3/ring.mp3');
1113 | setupCacheHandler();
1114 | });
1115 |
1116 | $("#phonebookbtn").click(function() {
1117 | var x = document.getElementById('phonebook');
1118 | if (x.style.display === 'none') {
1119 | x.style.display = 'block';
1120 | } else {
1121 | x.style.display = 'none';
1122 | }
1123 | });
1124 |
1125 | var cacheItems = ['login', 'passwd', 'yourname', 'domain', 'proxy', 'port',
1126 | 'pres1', 'pres1_label',
1127 | 'pres2', 'pres2_label',
1128 | 'pres3', 'pres3_label',
1129 | 'pres4', 'pres4_label',
1130 | 'pres5', 'pres5_label',
1131 | 'pres6', 'pres6_label',
1132 | 'pres7', 'pres7_label',
1133 | 'pres8', 'pres8_label',
1134 | 'pres9', 'pres9_label',
1135 | 'pres10', 'pres10_label',
1136 |
1137 | ];
1138 |
1139 | function setupCacheHandler() {
1140 | for(var i = 0; i < cacheItems.length; i++) {
1141 | var key = cacheItems[i];
1142 | var value = localStorage.getItem("saraphone." + key);
1143 | if (value) document.getElementById(key).value = value;
1144 | $("#" + key).change(function(e) {localStorage.setItem("saraphone." + e.target.id, e.target.value);});
1145 | }
1146 | }
1147 |
--------------------------------------------------------------------------------
/saraphone.html:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | SaraPhone WebRTC
42 |
43 |
44 |
45 |
46 |
47 |
62 |
63 |
64 |
Wait please...
65 |
66 |
475 |
476 |
477 |
478 |
479 |
483 |
484 |
485 |
486 |
--------------------------------------------------------------------------------