· 6 years ago · Dec 10, 2019, 11:48 AM
1Terrasoft.configuration.Structures["UsrOktellCtiProvider"] = {innerHierarchyStack: ["UsrOktellCtiProvider"]};
2define("UsrOktellCtiProvider", ["ServiceHelper"], function(ServiceHelper) {
3 function initOktell() {
4 delete(window.oktell);
5 Oktell = (function() {
6
7 var self = this,
8 debugMode = false,
9 logStr = "";
10
11 /**
12 * log to console if debugMode == true
13 */
14 var log = function() {
15 if ( debugMode ) {
16 var d = new Date();
17 var dd = d.getFullYear() + '-' + (d.getMonth()<10?'0':'') + d.getMonth() + '-' + (d.getDate()<10?'0':'') + d.getDate();
18 var t = (d.getHours()<10?'0':'') + d.getHours() + ':' + (d.getMinutes()<10?'0':'')+d.getMinutes() + ':' + (d.getSeconds()<10?'0':'')+d.getSeconds() + ':' +
19 (d.getMilliseconds() + 1000).toString().substr(1);
20 logStr += dd +' '+ t + ' | ';
21 args = ['Oktell.js ' + t + ' |']
22 for ( var i = 0, j = arguments.length; i < j; i++ ) {
23 logStr += (typeof arguments[i] == 'object' ? JSON.stringify(arguments[i]) : arguments[i]) + ' | ';
24 args.push( arguments[i] );
25 }
26 logStr += "\n\n";
27 try {
28 console.log.apply( console, args || [] );
29 } catch ( e ) {
30 debugMode = false;
31 }
32 }
33 };
34
35 /**
36 * md5
37 * @param str target
38 * @return {String}
39 */
40 var md5 = function(str) {
41 var xl;
42
43 var rotateLeft = function(lValue, iShiftBits) {
44 return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
45 };
46
47 var addUnsigned = function(lX, lY) {
48 var lX4, lY4, lX8, lY8, lResult;
49 lX8 = (lX & 0x80000000);
50 lY8 = (lY & 0x80000000);
51 lX4 = (lX & 0x40000000);
52 lY4 = (lY & 0x40000000);
53 lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
54 if (lX4 & lY4) {
55 return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
56 }
57 if (lX4 | lY4) {
58 if (lResult & 0x40000000) {
59 return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
60 } else {
61 return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
62 }
63 } else {
64 return (lResult ^ lX8 ^ lY8);
65 }
66 };
67
68 var _F = function(x, y, z) {
69 return (x & y) | ((~x) & z);
70 };
71 var _G = function(x, y, z) {
72 return (x & z) | (y & (~z));
73 };
74 var _H = function(x, y, z) {
75 return (x ^ y ^ z);
76 };
77 var _I = function(x, y, z) {
78 return (y ^ (x | (~z)));
79 };
80
81 var _FF = function(a, b, c, d, x, s, ac) {
82 a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
83 return addUnsigned(rotateLeft(a, s), b);
84 };
85
86 var _GG = function(a, b, c, d, x, s, ac) {
87 a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
88 return addUnsigned(rotateLeft(a, s), b);
89 };
90
91 var _HH = function(a, b, c, d, x, s, ac) {
92 a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
93 return addUnsigned(rotateLeft(a, s), b);
94 };
95
96 var _II = function(a, b, c, d, x, s, ac) {
97 a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
98 return addUnsigned(rotateLeft(a, s), b);
99 };
100
101 var convertToWordArray = function(str) {
102 var lWordCount;
103 var lMessageLength = str.length;
104 var lNumberOfWords_temp1 = lMessageLength + 8;
105 var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
106 var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
107 var lWordArray = new Array(lNumberOfWords - 1);
108 var lBytePosition = 0;
109 var lByteCount = 0;
110 while (lByteCount < lMessageLength) {
111 lWordCount = (lByteCount - (lByteCount % 4)) / 4;
112 lBytePosition = (lByteCount % 4) * 8;
113 lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount) << lBytePosition));
114 lByteCount++;
115 }
116 lWordCount = (lByteCount - (lByteCount % 4)) / 4;
117 lBytePosition = (lByteCount % 4) * 8;
118 lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
119 lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
120 lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
121 return lWordArray;
122 };
123
124 var wordToHex = function(lValue) {
125 var wordToHexValue = "",
126 wordToHexValue_temp = "",
127 lByte, lCount;
128 for (lCount = 0; lCount <= 3; lCount++) {
129 lByte = (lValue >>> (lCount * 8)) & 255;
130 wordToHexValue_temp = "0" + lByte.toString(16);
131 wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
132 }
133 return wordToHexValue;
134 };
135
136 var x = [],
137 k, AA, BB, CC, DD, a, b, c, d, S11 = 7,
138 S12 = 12,
139 S13 = 17,
140 S14 = 22,
141 S21 = 5,
142 S22 = 9,
143 S23 = 14,
144 S24 = 20,
145 S31 = 4,
146 S32 = 11,
147 S33 = 16,
148 S34 = 23,
149 S41 = 6,
150 S42 = 10,
151 S43 = 15,
152 S44 = 21;
153
154 // str = this.utf8_encode(str);
155 x = convertToWordArray(str);
156 a = 0x67452301;
157 b = 0xEFCDAB89;
158 c = 0x98BADCFE;
159 d = 0x10325476;
160
161 xl = x.length;
162 for (k = 0; k < xl; k += 16) {
163 AA = a;
164 BB = b;
165 CC = c;
166 DD = d;
167 a = _FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
168 d = _FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
169 c = _FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
170 b = _FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
171 a = _FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
172 d = _FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
173 c = _FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
174 b = _FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
175 a = _FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
176 d = _FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
177 c = _FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
178 b = _FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
179 a = _FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
180 d = _FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
181 c = _FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
182 b = _FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
183 a = _GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
184 d = _GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
185 c = _GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
186 b = _GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
187 a = _GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
188 d = _GG(d, a, b, c, x[k + 10], S22, 0x2441453);
189 c = _GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
190 b = _GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
191 a = _GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
192 d = _GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
193 c = _GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
194 b = _GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
195 a = _GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
196 d = _GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
197 c = _GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
198 b = _GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
199 a = _HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
200 d = _HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
201 c = _HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
202 b = _HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
203 a = _HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
204 d = _HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
205 c = _HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
206 b = _HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
207 a = _HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
208 d = _HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
209 c = _HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
210 b = _HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
211 a = _HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
212 d = _HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
213 c = _HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
214 b = _HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
215 a = _II(a, b, c, d, x[k + 0], S41, 0xF4292244);
216 d = _II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
217 c = _II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
218 b = _II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
219 a = _II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
220 d = _II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
221 c = _II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
222 b = _II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
223 a = _II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
224 d = _II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
225 c = _II(c, d, a, b, x[k + 6], S43, 0xA3014314);
226 b = _II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
227 a = _II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
228 d = _II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
229 c = _II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
230 b = _II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
231 a = addUnsigned(a, AA);
232 b = addUnsigned(b, BB);
233 c = addUnsigned(c, CC);
234 d = addUnsigned(d, DD);
235 }
236
237 var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
238
239 return temp.toLowerCase();
240 }
241
242 var utf8Decode = function(str_data) {
243 // http://kevin.vanzonneveld.net
244 // + original by: Webtoolkit.info (http://www.webtoolkit.info/)
245 // + input by: Aman Gupta
246 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
247 // + improved by: Norman "zEh" Fuchs
248 // + bugfixed by: hitwork
249 // + bugfixed by: Onno Marsman
250 // + input by: Brett Zamir (http://brett-zamir.me)
251 // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
252 // * example 1: utf8_decode('Kevin van Zonneveld');
253 // * returns 1: 'Kevin van Zonneveld'
254 var tmp_arr = [],
255 i = 0,
256 ac = 0,
257 c1 = 0,
258 c2 = 0,
259 c3 = 0;
260
261 str_data += '';
262
263 while (i < str_data.length) {
264 c1 = str_data.charCodeAt(i);
265 if (c1 < 128) {
266 tmp_arr[ac++] = String.fromCharCode(c1);
267 i++;
268 } else if (c1 > 191 && c1 < 224) {
269 c2 = str_data.charCodeAt(i + 1);
270 tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
271 i += 2;
272 } else {
273 c2 = str_data.charCodeAt(i + 1);
274 c3 = str_data.charCodeAt(i + 2);
275 tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
276 i += 3;
277 }
278 }
279
280 return tmp_arr.join('');
281 }
282
283 var utf8DecodePass = function(aa) {
284 var bb = '', c = 0;
285 for (var i = 0; i < aa.length; i++) {
286 c = aa.charCodeAt(i);
287 if (c > 127) {
288 if (c > 1024) {
289 if (c == 1025) {
290 c = 1016;
291 } else if (c == 1105) {
292 c = 1032;
293 }
294 bb += String.fromCharCode(c - 848);
295 }
296 } else {
297 bb += aa.charAt(i);
298 }
299 }
300 return bb;
301 }
302
303 var base64_decode = function base64_decode (data) {
304 // http://kevin.vanzonneveld.net
305 // + original by: Tyler Akins (http://rumkin.com)
306 // + improved by: Thunder.m
307 // + input by: Aman Gupta
308 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
309 // + bugfixed by: Onno Marsman
310 // + bugfixed by: Pellentesque Malesuada
311 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
312 // + input by: Brett Zamir (http://brett-zamir.me)
313 // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
314 // - depends on: utf8_decode
315 // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
316 // * returns 1: 'Kevin van Zonneveld'
317 // mozilla has this native
318 // - but breaks in 2.0.0.12!
319 //if (typeof this.window['btoa'] == 'function') {
320 // return btoa(data);
321 //}
322 var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
323 var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
324 ac = 0,
325 dec = "",
326 tmp_arr = [];
327
328 if (!data) {
329 return data;
330 }
331
332 data += '';
333
334 do { // unpack four hexets into three octets using index points in b64
335 h1 = b64.indexOf(data.charAt(i++));
336 h2 = b64.indexOf(data.charAt(i++));
337 h3 = b64.indexOf(data.charAt(i++));
338 h4 = b64.indexOf(data.charAt(i++));
339
340 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
341
342 o1 = bits >> 16 & 0xff;
343 o2 = bits >> 8 & 0xff;
344 o3 = bits & 0xff;
345
346 if (h3 == 64) {
347 tmp_arr[ac++] = String.fromCharCode(o1);
348 } else if (h4 == 64) {
349 tmp_arr[ac++] = String.fromCharCode(o1, o2);
350 } else {
351 tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
352 }
353 } while (i < data.length);
354
355 dec = tmp_arr.join('');
356 dec = utf8Decode(dec);
357
358 return dec;
359 }
360
361 /**
362 * Extending object
363 * @param obj
364 * @return {*}
365 */
366 var extend = function(obj) {
367 var args = Array.prototype.slice.call(arguments, 1);
368 each(args, function(arg,kk) {
369 each(arg, function(a,prop) {
370 if ( arg.hasOwnProperty(prop) ) {
371 obj[prop] = a;
372 }
373 });
374 });
375 return obj;
376 };
377
378 /**
379 * Check if target is array
380 * @param obj target
381 * @return {Boolean}
382 */
383 var isArray = function(obj) {
384 if ( Array.isArray ) {
385 return Array.isArray(obj);
386 } else {
387 return Object.prototype.toString.call(obj) == '[object Array]';
388 }
389 }
390
391 /**
392 * Object cloning (don't work with functions) TODO: throw error if circular links
393 * @param obj
394 * @param useJSON
395 * @return {*}
396 */
397 var cloneObject = function( obj, useJSON ) { // don't work with functions as properties
398 if ( useJSON ) {
399 return JSON.parse(JSON.stringify(obj));
400 } else {
401 var c = {};
402 for ( var i in obj ){
403 if ( obj.hasOwnProperty(i) ) {
404 if ( typeof obj[i] == 'object' ) {
405 c[i] = cloneObject(obj[i],false);
406 } else {
407 c[i] = obj[i];
408 }
409 }
410 }
411 return c;
412 }
413 };
414
415 /**
416 * Array's or object's size
417 * @param obj
418 * @return {*}
419 */
420 var size = function(obj) {
421 obj = obj || [];
422 if ( isArray(obj) ) {
423 return obj.length;
424 } else if ( obj === Object(obj) ) {
425 if ( Object.keys ){
426 return Object.keys(obj).length;
427 } else {
428 var keysCount = 0;
429 for (var key in obj) if ( Object.prototype.hasOwnProperty.call(obj, key) ) { keysCount++; }
430 return keysCount;
431 }
432 }
433 return false;
434 };
435
436 var breaker = {};
437 /**
438 * foreach with callback
439 * @param obj
440 * @param fn
441 * @param context
442 */
443 var each = function(obj, fn, context) {
444 if (obj == null) return;
445 if ( Array.prototype.forEach && obj.forEach === Array.prototype.forEach ) {
446 obj.forEach(fn, context);
447 } else if ( obj.length === +obj.length ) {
448 for (var i = 0, l = obj.length; i < l; i++) {
449 if (i in obj && fn.call(context, obj[i], i, obj) === breaker) return;
450 }
451 } else {
452 for (var key in obj) {
453 if ( Object.prototype.hasOwnProperty.call(obj, key) ) {
454 if (fn.call(context, obj[key], key, obj) === breaker) return;
455 }
456 }
457 }
458 }
459
460 var trim = function(val) {
461 return val.replace(/^\s+/, '').replace(/\s+$/, '');
462 }
463
464 /**
465 * Format phone number
466 * @param value
467 * @return {String}
468 */
469 var formatPhone = function( value ) {
470 if ( ! value ) { return '';}
471
472 value = value.toString().split(';').join(',');
473
474 var phones = value.split(',');
475
476 for( var i = 0; i < phones.length; i++ ) {
477 phones[i] = trim( phones[i] );
478 var phone
479 , country = ""
480 , city = ""
481 , extra = "";
482
483 if ( phones[i] == "" ) { continue; }
484
485 if ( phones[i].indexOf( '(' ) != -1 ) {
486
487 var tmp = phones[i].split('(');
488 country = trim( tmp[0] );
489
490 tmp = tmp[1].split(')');
491 city = trim( tmp[0] );
492
493 var phone = trim( tmp[1] );
494 phone = phone.replace( /(.?[0-9]) ([0-9].?)/ig, "$1-$2" );
495 phone = phone.replace( /(.?[0-9]) ([0-9].?)/ig, "$1-$2" );
496
497 if ( phone.indexOf('-') == -1 ) {
498
499 tmp = [ phone.split(' ')[0], phone.split(' ').slice(1).join(' ') ];
500 phone = trim( tmp[0] );
501 extra = trim( tmp[1] );
502
503 if ( phone.length == 5 ) { phone = phone.substr( 0, 3 ) + "-" + phone.substr( 3, 2 ); }
504 if ( phone.length == 6 ) { phone = phone.substr( 0, 2 ) + "-" + phone.substr( 2, 2 ) + "-" + phone.substr( 4, 2 ); }
505 if ( phone.length == 7 ) { phone = phone.substr( 0, 3 ) + "-" + phone.substr( 3, 2 ) + "-" + phone.substr( 5, 2 ); }
506
507 if ( extra != "" ) { phone += ' ' + extra; }
508 }
509
510 } else {
511
512 phone = phones[i].split('+').join('');
513 phone = phone.replace( /(.?[0-9]) ([0-9].?)/ig, "$1-$2" );
514 phone = phone.replace( /(.?[0-9]) ([0-9].?)/ig, "$1-$2" );
515
516 var tmp = [ phone.split(' ')[0], phone.split(' ').slice(1).join(' ') ];
517 phone = trim( tmp[0] );
518 phone = phone.split('-').join('');
519 phone = phone.split('?').join('');
520 extra = trim( tmp[1] );
521
522 if ( phone.length == 5 ) { phone = phone.substr( 0, 3 ) + "-" + phone.substr( 3, 2 ); }
523 else if ( phone.length == 6 ) { phone = phone.substr( 0, 2 ) + "-" + phone.substr( 2, 2 ) + "-" + phone.substr( 4, 2 ); }
524 else if ( phone.length == 7 ) { phone = phone.substr( 0, 3 ) + "-" + phone.substr( 3, 2 ) + "-" + phone.substr( 5, 2 ); }
525 else if ( phone.length == 9 ) { city = phone.substr( 0, 3 ); phone = phone.substr( 3, 2 ) + "-" + phone.substr( 5, 2 ) + "-" + phone.substr( 7, 2 ); }
526 else if ( phone.length == 10 ) { city = phone.substr( 0, 3 ); phone = phone.substr( 3, 3 ) + "-" + phone.substr( 6, 2 ) + "-" + phone.substr( 8, 2 ); }
527 else if ( phone.length == 11 ) { country = phone.substr( 0, 1 ); city = phone.substr( 1, 3 ); phone = phone.substr( 4, 3 ) + "-" + phone.substr( 7, 2 ) + "-" + phone.substr( 9, 2 ); }
528 else if ( phone.length == 12 ) { country = phone.substr( 0, 2 ); city = phone.substr( 2, 3 ); phone = phone.substr( 5, 3 ) + "-" + phone.substr( 8, 2 ) + "-" + phone.substr( 10, 2 ); }
529 else if ( phone.length == 13 ) { country = phone.substr( 0, 3 ); city = phone.substr( 3, 3 ); phone = phone.substr( 6, 3 ) + "-" + phone.substr( 9, 2 ) + "-" + phone.substr( 11, 2 ); }
530 else if ( phone.length == 14 ) { country = phone.substr( 0, 4 ); city = phone.substr( 4, 3 ); phone = phone.substr( 7, 3 ) + "-" + phone.substr( 10, 2 ) + "-" + phone.substr( 12, 2 ); }
531
532 if ( extra != "" ) { phone += ' ' + extra; }
533 }
534
535 if ( country == "8" ) { country = "+7"; }
536 if ( country[0] != "+" && country != "" ) { country = "+" + country; }
537
538 if ( true ) { // collect
539 var full = [];
540 if ( country != "" ) { full.push( country ); }
541 if ( city != "" ) { full.push( "(" + city + ")" ); }
542 if ( phone != "" ) { full.push( phone ); }
543
544 phones[i] = full.join(' ');
545 }
546 }
547
548 value = phones.join(', ');
549 return value;
550 };
551
552 /**
553 * create new guid
554 * @return {String}
555 */
556 var newGuid = function() {
557 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
558 var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
559 return v.toString(16);
560 });
561 };
562
563 var buildParams = function(obj) {
564 if ( typeof obj == 'object' ) {
565 var str = '';
566 each(obj, function(v,k) {
567 str += '&' + k + '=' + v.toString()
568 });
569 return str;
570 }
571 return false
572 };
573
574 /**
575 * target is guid or not
576 * @param str
577 * @return {Boolean}
578 */
579 var isGuid = function(str) {
580 if ( typeof str == 'string' && ( str.match(/[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}/)) || ( str.length == 32 && str.match(/[a-zA-Z0-9]{32}/)) ) {
581 return true;
582 }
583 return false;
584 };
585
586 /**
587 * call target if it is function
588 * @param fn
589 */
590 var callFunc = function(fn) {
591 if ( typeof fn == 'function' ) fn.apply(undefined, Array.prototype.slice.call( arguments, 1 ));
592 }
593
594 var dateToIso = function(dt) {
595 if ( dt instanceof Date ) {
596 return dt.getFullYear() + '-' + ( dt.getMonth() < 10 ? '0' + dt.getMonth() : dt.getMonth() ) + '-' + ( dt.getDate() < 10 ? '0' + dt.getDate() : dt.getDate() );
597 }
598 return false;
599 }
600
601 var cookie = function(key, value, options) {
602
603 // key and at least value given, set cookie...
604 if (arguments.length > 1 && String(value) !== "[object Object]") {
605 options = extend({}, options);
606
607 if (value === null || value === undefined) {
608 options.expires = -1;
609 }
610
611 if (typeof options.expires === 'number') {
612 var seconds = options.expires, t = options.expires = new Date();
613 t.setSeconds(t.getSeconds() + seconds);
614 }
615
616 value = String(value);
617
618 return (document.cookie = [
619 encodeURIComponent(key), '=',
620 options.raw ? value : encodeURIComponent(value),
621 options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
622 options.path ? '; path=' + options.path : '',
623 options.domain ? '; domain=' + options.domain : '',
624 options.secure ? '; secure' : ''
625 ].join(''));
626 }
627
628 // key and possibly options given, get cookie...
629 options = value || {};
630 var result, decode = options.raw ? function(s) { return s; } : decodeURIComponent;
631 return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
632 };
633
634 var eventSplitter = /\s+/;
635 var normalizeEventNames = function(eventNames) {
636 if ( typeof eventNames == 'string' ) {
637 eventNames = eventNames.replace(/,/g, ' ').split(eventSplitter);
638 } else if ( isArray(eventNames) && eventNames.length > 0 ) {
639 var eventsArray = [];
640 for (var i = 0; i < eventNames.length; i++) {
641 var event = eventNames[i];
642 if ( event && typeof event == 'string' ) {
643 eventsArray.push(event);
644 }
645 }
646 eventsNames = eventsArray;
647 } else {
648 return false;
649 }
650 return eventNames;
651 }
652 /**
653 * Events object. For extending other objects
654 * @type {Object}
655 */
656
657 var Events = {
658 /**
659 * Subscribe to events
660 * @param eventNames
661 * @param callback
662 * @param context
663 * @return {Boolean}
664 */
665 on: function( eventNames, callback, context ) {
666 eventNames = normalizeEventNames(eventNames);
667 if ( ! eventNames || typeof callback != 'function' ) {
668 return false;
669 }
670
671 var calls = this._callbacks || ( this._callbacks = {} );
672 each( eventNames, function(event,key) {
673 if ( typeof event != 'string' ) {
674 return breaker;
675 }
676 var eventCalls = calls[ event ] || ( calls[ event ] = [] );
677 eventCalls.push({
678 callback: callback,
679 context: context
680 });
681 });
682 return true;
683 },
684 /**
685 * Unsubscribe
686 * @param eventNames to unsubscribe, if empty - unsubscribe from all events
687 * @param callback to unsubscribe, if empty - unsubscribe from all eventNames
688 * @return {Boolean}
689 */
690 off: function( eventNames, callback ) {
691
692 var calls = this._callbacks || ( this._callbacks = {} );
693
694 if ( ! eventNames ) {
695 calls = {};
696 } else {
697 eventNames = normalizeEventNames(eventNames);
698 if ( ! eventNames ) {
699 return false;
700 }
701
702 if ( typeof callback == 'function' ) {
703 each(eventNames, function(event) {
704 if ( typeof event != 'string' ) { return; }
705 each(calls[event], function(cl,i) {
706 if ( cl && cl.callback === callback ) {
707 delete calls[ event ][i];
708 }
709 });
710 });
711 } else {
712 each(eventNames, function(event) {
713 delete calls[ event ];
714 });
715 }
716 }
717 return true;
718 },
719 /**
720 * Trigger event with or without additional params
721 * @param eventNames
722 * @return {Boolean}
723 */
724 trigger: function( eventNames ) {
725 eventNames = normalizeEventNames(eventNames);
726 var calls = this._callbacks || ( this._callbacks = {} );
727 if ( ! eventNames ) {
728 return false;
729 }
730 var args = Array.prototype.slice.call( arguments, 1 );
731 var allEventCalls = calls['all'];
732 each( eventNames, function(event) {
733 var eventCalls = calls[ event ];
734 if ( eventCalls ) {
735 each(eventCalls, function(eventCall) {
736 if ( eventCall && typeof eventCall.callback == 'function' ) {
737 eventCall.callback.apply( eventCall.context || undefined, args );
738 }
739 });
740 }
741 if ( allEventCalls ) {
742 var allEventArgs = [event].concat(args);
743 each(allEventCalls, function(eventCall) {
744 if ( eventCall && typeof eventCall.callback == 'function' ) {
745 eventCall.callback.apply( eventCall.context || undefined, allEventArgs );
746 }
747 });
748 }
749 });
750 return true;
751 }
752 };
753
754 /**
755 * class for connecting and working with browser's websocket API
756 * @param url ##### #######
757 * @param openTimeout ####### ###########
758 * @param onOpenCallback #######
759 * @constructor
760 */
761 var Server = function( url, openTimeout, delayMin, delayMax, onOpenCallback ) {
762 var ws,
763 wsArr = {},
764 wsUrlRegexp = /^ws[s]{0,1}:\/\/\S+$/i,
765 self = this,
766 wsWasOpened = false,
767 wsErrorConnection = false,
768 callbacks = {},
769 multiparts = {},
770 oktellEventCallbacks = {},
771 currentSessionSubscriptions = {},
772 eventGroups = {
773 'dynamic': ['executemethod', 'cancelmethod'],
774 'dynamicwaitabort': ['executemethodwaitaborted'],
775 'chat': ['chatmessageviewed', 'chatmessage', 'chatmemberremoved', 'chatmemberadded', 'chatnamechanged', 'chatcreated'],
776 'dlgcard': ['dlgcard_showreserve', 'dlgcard_showconfirm', 'dlgcard_showformstop', 'dlgcard_showformdialog', 'dlgcard_closeall', 'dlgcard_closereserve', 'dlgcard_closeformreturnvalues', 'dlgcard_closeformreturncomment']
777 };
778
779 self.setQueryDelayMin(delayMin);
780 self.setQueryDelayMax(delayMax);
781
782 var parseUrls = function(urls) {
783 if ( ! isArray(urls) ) {
784 return false;
785 }
786 var needSecure = location.protocol == 'https:' ? true : false,
787 defaultPort = 80,
788 result = [];
789
790 for ( var i, l = urls.length; i < l; i++ ) {
791 if ( typeof urls[i] != 'string' ) {
792 return false;
793 }
794 if ( wsUrlRegexp.text(urls[i]) ) {
795 result.push(urls[i]);
796 } else {
797 var uArr = urls[i].split(':'),
798 host = uArr[0],
799 port = uArr[1];
800 if ( ! port ) {
801 port = defaultPort;
802 result.push( host + ':' + '4066' ); //
803 }
804 if ( port == '443' ) { needSecure = true; }
805 result.push( host + ':' + port );
806 }
807 }
808
809 var prefix = needSecure ? 'wss://' : 'ws//';
810 for ( var i, l = result.length; i < l; i++ ) {
811 if ( ! wsUrlRegexp.text(urls[i]) ) {
812 result[i] = prefix + result[i];
813 }
814 }
815
816 }
817 var n_onClose = function(a,b,c) {}
818 var n_onError = function(a,b,c) {}
819 var n_onError = function(a,b,c) {}
820 var n_wasConnected = false;
821 var n_onConnect = function(wsObj) {
822 if ( ! n_wasConnected ) {
823 n_wasConnected = true;
824 ws = wsObj;
825 // send ping, wait pong, redirect to secure if need
826 var qid = Math.random().toString();
827 ws.onmessage = function( evt ) {
828
829 var data = JSON.parse( evt.data );
830
831 var afterSuccessConnect = function(finalWs) {
832 self.ws = finalWs;
833 finalWs.onmessage = onMessage;
834 finalWs.onclose = n_onClose;
835 finalWs.onerror = n_onError;
836 onOpen()
837 }
838
839 if ( data[0] == 'websocketredirect' ) {
840 var wss = new WebSocket( wsObj.url.replace('ws://', 'wss://').replace(':4066', ':443'), 'json');
841 wss.onopen = function() {
842 afterSuccessConnect(wss);
843 }
844 } else if ( data[1] && data[1].qid == qid ) {
845 afterSuccessConnect(wsObj);
846 }
847 }
848 ws.send( JSON.stringify(['ping',{qid:qid}]));
849 } else {
850 wsObj.close();
851 }
852 }
853
854 self.n_connect = function() {
855 var wsArr = [];
856 var urls = parseUrls(url);
857 for ( var i, l = urls.length; i < l; i++ ) {
858 setTimeout(function() {
859 var ws = new WebSocket(urls[i], 'json');
860 ws.onopen = function() {
861 n_onConnect(ws);
862 }
863 ws.onerror = function() {
864
865 }
866 ws.onclose = function() {
867
868 }
869 },1);
870 }
871 }
872
873 self.url = url;
874
875 var errorConnection = function() {
876 if ( ! wsErrorConnection ) {
877 wsErrorConnection = true;
878 self.trigger('errorConnection');
879 }
880 };
881
882 var onOpen = function() {
883 wsWasOpened = true;
884 if ( typeof onOpenCallback == 'function' ) {
885 log('success connect to ' + ws.url)
886 onOpenCallback(ws.url);
887 }
888 }
889
890 var onMessage = function( evt ) {
891
892 var data = JSON.parse( evt.data );
893
894 triggerOktellEvent(data);
895
896 var isFullMultiPart = false;
897 if ( data[0] == 'multipart' ) {
898 var msg = multiparts[ data[1]['message-id'] ];
899 if ( !msg ) {
900 msg = {
901 packetcount:data[1]['packetcount'],
902 content:[],
903 value:''
904 };
905 multiparts[ data[1]['message-id'] ] = msg;
906 }
907 msg.content[ parseInt( data[1]['packetnumber'] ) ] = data[1]['content'].toString();
908 if ( msg.content.length == msg.packetcount ) {
909 for ( var i = 0; i < msg.content.length; i++ ) {
910 msg.value = '' + msg.value + base64_decode( msg.content[i] );
911 }
912 isFullMultiPart = true;
913 }
914 }
915
916 if ( data[0] != 'multipart' || ( data[0] == 'multipart' && isFullMultiPart ) ) {
917 if ( isFullMultiPart ) {
918 data = JSON.parse( multiparts[ data[1]['message-id'] ].value );
919 }
920
921 if ( typeof callbacks[data[1].qid] == 'function' ) {
922 //debug('callback');
923 var c = callbacks[data[1].qid];
924 delete callbacks[data[1].qid];
925 var d = data[1];
926 if (d.result === undefined) {d.result = 1;}
927 c( data[1] );
928 }
929 }
930 };
931
932 var onClose = function() {
933 if ( wsWasOpened ) {
934 if ( ! wsErrorConnection ) {
935 self.trigger('connectionClose');
936 }
937 } else {
938 errorConnection();
939 }
940 currentSessionSubscriptions = {};
941 };
942
943 self.multiConnect = function() {
944
945 if ( ! isArray(url) ) {
946 url = [url];
947 }
948
949 log('Multi connect start', url);
950
951 var connectErrorsCount = 0;
952
953 url = url.slice(0,10);
954 each(url, function( curl, i) {
955
956 setTimeout(function() {
957 try {
958 wsArr[curl] = new WebSocket( curl , 'json');
959 log('trying to connect ' + curl);
960
961 wsArr[curl].onopen = function() {
962 wsArr[curl].wasOpened = true
963 var qid = Math.random().toString();
964 wsArr[curl].send( JSON.stringify(['ping',{qid:qid}]));
965 wsArr[curl].onmessage = function( evt ) {
966 if ( wsWasOpened ) {
967 //log('onopen return false for ' + curl);
968 return false;
969 }
970 var data = JSON.parse( evt.data );
971
972 var afterSuccessConnect = function() {
973 self.url = curl;
974 self.wsUrl =
975 ws = wsArr[curl];
976 ws.onmessage = onMessage
977 ws.onclose = onClose;
978 onOpen()
979 }
980
981 if ( data[0] == 'websocketredirect' ) {
982 //if ( data[0] == 'pong' ) {
983 var wssUrl = curl.replace(/^ws:\/\//, 'wss://').replace(/:[0-9]{1,5}/, ':443');
984 log('redirect to secure websocket, trying to connect ' + wssUrl);
985 wsArr[curl].close();
986 curl = wssUrl;
987 var wss = new WebSocket( curl, 'json');
988 wss.onopen = function() {
989 if ( wsWasOpened ) {
990 //log('onopen return false for ' + curl);
991 return false;
992 }
993 afterSuccessConnect()
994 }
995 wsArr[curl] = wss
996
997 } else if ( data[1] && data[1].qid == qid ) {
998 afterSuccessConnect()
999 }
1000 }
1001 }
1002
1003 setTimeout(function() {
1004 //log('timeout for ' + curl + ' ' + self.getWebSocketState(wsArr[curl]));
1005 if ( ( self.getWebSocketState(wsArr[curl]) != 1 && ! wsArr[curl].wasOpened ) || self.url != curl ) {
1006 //log('timeout2 for ' + curl);
1007 self.disconnect(wsArr[curl]);
1008 connectErrorsCount++;
1009
1010 if ( connectErrorsCount == url.length ) {
1011 //log('errorConnection() for ' + curl);
1012 connectErrorsCount = -999;
1013 errorConnection();
1014 }
1015 }
1016 }, openTimeout);
1017
1018 } catch (e) {
1019 //log('exception for ' + curl);
1020 connectErrorsCount++;
1021
1022 if ( connectErrorsCount == url.length ) {
1023 //log('trigger errorConnection for ' + curl);
1024 connectErrorsCount = -999;
1025 self.trigger('errorConnection', e);
1026 }
1027
1028 return breaker;
1029 }
1030
1031 },1);
1032
1033 });
1034
1035 };
1036
1037 self.connect = function() {
1038 wsErrorConnection = false;
1039 try {
1040 log('trying to connect ' + url);
1041 ws = new WebSocket( 'ws://'+url, 'json');
1042
1043 setTimeout(function() {
1044 if ( self.getWebSocketState() == 0 ) {
1045 self.disconnect();
1046 errorConnection();
1047 }
1048 }, openTimeout);
1049
1050 } catch (e) {
1051 self.trigger('errorConnection', e);
1052 return false;
1053 }
1054
1055
1056 ws.onopen = onOpen;
1057 ws.onmessage = onMessage;
1058 ws.onclose = onClose;
1059 }
1060
1061
1062 self.send = function( data, id, callback ) {
1063 var d = JSON.parse(data);
1064 if ( typeof callback == 'function' ) {
1065 callbacks[id] = callback;
1066 }
1067 if ( self.delayMin > 0 ) {
1068 var timeout = self.delayMin;
1069 if ( delayMax ) {
1070 timeout = Math.round( Math.random() * Math.abs(self.delayMax - self.delayMin) + self.delayMin );
1071 }
1072 setTimeout(function() {
1073 ws.send(data);
1074 }, timeout);
1075 return true
1076 } else {
1077 return ws.send( data );
1078 }
1079 }
1080
1081 self.sendOktell = function( method, body, callback ) {
1082 body = body || {};
1083 var msg = new Array();
1084 msg.push( method );
1085 body.qid = Math.random().toString();
1086 msg.push( body );
1087 if ( self.send( JSON.stringify( msg ), msg[1].qid, callback ) === false ) {
1088 callFunc(callback,{result:0,errormsg:'websocket send error'});
1089 }
1090 }
1091
1092 self.execProc = function( procName, paramsObj, callback ) {
1093 var msg = [
1094 'execpredefineddbstoredproc',
1095 extend({
1096 qid:Math.random().toString(),
1097 procedure:procName
1098 }, paramsObj)
1099 ];
1100 self.send( JSON.stringify( msg ), msg[1].qid, function(data) {
1101 var items = [];
1102 if ( data.result == 1 && data.errorcode == 0 ) {
1103 for( var i = 0; i < data.dataset.length; i ++ ) {
1104 var d = [];
1105 items.push(d);
1106 var keys = [];
1107 for ( var k = 0; k < data.dataset[i][0].length; k ++ ){
1108 keys.push( data.dataset[i][0][k] );
1109 }
1110 for ( var j = 1; j < data.dataset[i].length; j++ ) {
1111 var item = {};
1112 for ( var f = 0; f < keys.length; f++ ) {
1113 item[ keys[f] ] = data.dataset[i][j][f];
1114 }
1115 d.push( item );
1116 }
1117 }
1118 } else {
1119 items = false;
1120 }
1121 callFunc(callback,items, data.dataset);
1122 });
1123 };
1124
1125 self.bindOktellEvent = function( eventNames, callback ) {
1126 eventNames = normalizeEventNames(eventNames);
1127 if ( ! eventNames || typeof callback != 'function' ) {return false;}
1128
1129 each(eventNames, function(event) {
1130 if ( ! oktellEventCallbacks[event] ) {
1131 oktellEventCallbacks[event] = [];
1132 }
1133 oktellEventCallbacks[event].push( callback );
1134 });
1135
1136 self.sendOktellEventSubscription(eventNames);
1137
1138 return true;
1139 };
1140
1141 var triggerOktellEvent = function(data) {
1142 if ( oktellEventCallbacks && oktellEventCallbacks[ data[0] ] ) {
1143 log('<<< EVENT ' + data[0], data[1]);
1144 each( oktellEventCallbacks[ data[0] ], function(callback) {
1145 callFunc(callback,data[1]);
1146 });
1147 }
1148 }
1149
1150 self.sendOktellEventSubscription = function(eventNames, dontSend) {
1151 var self = this;
1152 eventNames = normalizeEventNames(eventNames)
1153 if ( ! eventNames ) {
1154 return false;
1155 }
1156
1157 var toSend = [];
1158
1159 each( eventNames, function(event) {
1160 if ( ! currentSessionSubscriptions[ event ] ) {
1161 toSend.push(event)
1162 if ( isArray(eventGroups[event]) ) {
1163 self.sendOktellEventSubscription(eventGroups[event], true);
1164 }
1165 }
1166 if ( dontSend ) {
1167 currentSessionSubscriptions[ event ] = true;
1168 }
1169 });
1170
1171 if ( ! dontSend && toSend.length ) {
1172 log ('===> Event subscription', toSend);
1173 self.sendOktell('subscribeevent', {eventmethod: toSend}, function(data) {
1174 log('<=== Event subscribtion result: ' + data.result, toSend)
1175 each( toSend, function(ev) {
1176 currentSessionSubscriptions[ ev ] = true;
1177 });
1178 });
1179 }
1180 };
1181
1182 /**
1183 * Unsubscribe from native event of oktell server
1184 * @param eventNames
1185 * @param callback
1186 * @return {Boolean}
1187 */
1188 self.unbindOktellEvent = function( eventNames, callback ) {
1189 if ( ! eventNames ) {
1190 oktellEventCallbacks = {};
1191 } else {
1192 eventNames = normalizeEventNames(eventNames);
1193 if ( ! eventNames ) { return false; }
1194 callback = typeof callback == 'function' ? callback : false;
1195
1196 for (var i = 0; i < eventNames.length; i++) {
1197 var event = eventNames[i];
1198 if ( callback ) {
1199 each( oktellEventCallbacks[event], function(cb,i) {
1200 if ( cb === callback ) {
1201 delete oktellEventCallbacks[event][i];
1202 }
1203 });
1204 } else {
1205 delete oktellEventCallbacks[event];
1206 }
1207 }
1208 }
1209 return true;
1210 };
1211
1212 self.reSendOktellEventSubscribtions = function() {
1213
1214 var events = [];
1215 each( currentSessionSubscriptions, function(v,ev) {
1216 if ( v ) {
1217 events.push(ev);
1218 }
1219 });
1220
1221 if ( events.length ) {
1222 self.sendOktell('subscribeevent', {eventmethod: events}, function(data) {
1223
1224 });
1225 }
1226 };
1227
1228 self.disconnect = function( websocket ) {
1229 websocket = websocket || ws;
1230 websocket.close();
1231 var status = self.getWebSocketState(websocket);
1232 if ( status == 3 || status == 2 ) {
1233 return true;
1234 } else {
1235 return false;
1236 }
1237 };
1238
1239 self.getWebSocketState = function( websocket ) {
1240 websocket = websocket || ws;
1241 return websocket ? websocket.readyState : undefined;
1242 }
1243 };
1244 Server.prototype.setQueryDelayMin = function(delay) {
1245 delay = parseInt(delay);
1246 if ( delay ) {
1247 this.delayMin = delay;
1248 }
1249 };
1250 Server.prototype.setQueryDelayMax = function(delay) {
1251 delay = parseInt(delay);
1252 if ( delay ) {
1253 this.delayMax = delay;
1254 }
1255 };
1256 extend( Server.prototype , Events );
1257
1258 var Abonent = function() {
1259
1260 };
1261
1262 var Oktell = function( options ) {
1263 var self = this,
1264 server,
1265 _oktellConnected = false,
1266 nativeEventsForBindAfterConnect = [],
1267 currentUrlIndex = 0,
1268 pingTimer,
1269 queueTimer,
1270 oktellOptions = {
1271 openTimeout: 10000,
1272 queryTimeout: 20000,
1273 queueInterval: 5000,
1274 oktellVoice: false
1275 },
1276 oktellVoice,
1277 sipPhone,
1278 sipPnoneActive = false,
1279 oktellInfo = {
1280 redirectNumber: undefined,
1281 allowedProcedures: {}
1282 },
1283 methodVersions = {
1284 getmyuserinfo: {v:120327, critical: true},
1285 getversion: { v:120112, critical: true },
1286 pbxmakeflash: {v:120725},
1287 getextendedlineinfo: {v:120112, critical: true},
1288 getflashedabonentinfo: {v:120112, critical: true},
1289 saveredirectrules: {v:120725},
1290 deleteredirectrules: {v:120725},
1291 getredirectrules: {v:120725},
1292 pbxmaketransfer: {v:120725},
1293 triggercustomevent: {v:120725},
1294 getallusernumbers: {v:120920},
1295 cc_getlunchtypes: {v:130101},
1296 pbxanswercall: {v:131218}
1297 },
1298 httpQueryData = {},
1299 cookieSessionName = '___oktellsessionid',
1300
1301 users = {},
1302 numbers = {},
1303 numbersById = {},
1304 connectionClosedByUser = false;
1305
1306 var exportApi = function(name, fn, context) {
1307 if ( ! self[name] && typeof fn == 'function' ) {
1308 self[name] = function() {
1309 return fn.apply( context || self, arguments );
1310 }
1311 }
1312 }
1313
1314 var oktellConnected = function(connected) {
1315 if ( connected !== undefined ) {
1316 if ( connected ) {
1317 _oktellConnected = true;
1318 } else {
1319 _oktellConnected = false;
1320 }
1321 }
1322 return _oktellConnected;
1323 }
1324
1325 /**
1326 * Events
1327 * @type {*}
1328 */
1329 var events = extend({}, Events);
1330
1331 /**
1332 * Return state of connection with websocket server
1333 * @return {Boolean}
1334 */
1335 var serverConnected = function() {
1336 if ( server && server.getWebSocketState() == 1 ) {
1337 return true;
1338 }
1339 return false;
1340 }
1341
1342 /**
1343 * Return name of state if state found, or false
1344 * @param code of state
1345 * @param states Object with states ( key is code, val is state name )
1346 * @return {*}
1347 */
1348 var getStateByCode = function( code, states ) {
1349 if ( code === undefined || ! size(states) ) {
1350 return false;
1351 }
1352 code = parseInt( code );
1353 var msg = '';
1354 each( states, function(scode, message) {
1355 if ( scode == code ) {
1356 msg = message.toLowerCase();
1357 }
1358 });
1359 return msg;
1360 };
1361
1362 /**
1363 * Convert target to array of strings
1364 * @param strings - string or array of string
1365 * @return {*} array or false
1366 */
1367 var toStringsArray = function(strings) {
1368 if ( ! strings || !(typeof strings == 'string' || typeof strings == 'number' || isArray(strings)) ) { return false; }
1369 if ( typeof strings == 'string' || typeof strings == 'number' ) {
1370 strings = [strings.toString()];
1371 }
1372 var result = true;
1373 each(strings, function(s) {
1374 if( typeof s != 'string' ) { result = false; return breaker; }
1375 });
1376 if ( ! result ){ return false; } else { return strings }
1377 }
1378
1379 /**
1380 * Check oktell websocket method's version
1381 * @param method name
1382 * @return {Boolean} true if supported, false if not
1383 */
1384 var isValidMethodVersion = function( method ) {
1385 if ( oktellInfo.oktellDated && methodVersions[method] && oktellInfo.oktellDated < methodVersions[method].v ) {
1386 return false;
1387 }
1388 return true;
1389 };
1390
1391// var connectErrors = {
1392// 10: 'error',
1393// 11: 'ws login method return error',
1394// 12: 'desktop client is connected now',
1395// 13: 'wrong login/pass combination',
1396// 14: 'session is not exist and no password param',
1397// 15: 'error loading phone state',
1398// 16: 'error loading user state',
1399// 17: 'error loading user info',
1400// 18: 'error loading version info',
1401// 19: 'bad url param'
1402// 20: 'max online users count reached'
1403// }
1404// var getConnectErrorObj = function(code, msg) {
1405// return { errorCode: code, errorMessage: connectErrors[code] + ( msg ? ' ' + msg : '') }
1406// }
1407
1408 /**
1409 * Possible disconnect reasons
1410 * @type {Object}
1411 */
1412 var disconnectReasons = {
1413 10: 'critical ws method not supported by this version of Oktell server',
1414 11: 'error loading version info',
1415 12: 'websocket connection closed',
1416 13: 'disconnected by user',
1417 14: "can't login using oktell.connect"
1418 };
1419
1420 /**
1421 * Return disconnect reason object
1422 * @param code from disconnectReasons
1423 * @param msg that will be concatenated to reason message
1424 * @return {Object}
1425 */
1426 var getDisconnectReasonObj = function(code,msg) {
1427 return {
1428 code: code,
1429 message: ( disconnectReasons[code] + ' ' + (msg||'') ) || ''
1430 }
1431 };
1432
1433 /**
1434 * Possible errors
1435 * @type {Object}
1436 */
1437 var errorTypes = {
1438 // common
1439 1000: 'something goes wrong',
1440 // exec
1441 1101: 'method not supported by current Oktell version',
1442 1102: 'server didnt understand method or response timeout',
1443 1103: 'error execute method',
1444 1104: 'bad method for execute',
1445 1105: 'error execute stored procedure',
1446 1106: 'bad params',
1447 // connect
1448 1200: 'cant connect to server',
1449 1201: 'error websocket connection',
1450 1202: 'error login\pass',
1451 1203: 'oktell version too old',
1452 1204: 'using oktell desktop client',
1453 1205: 'error url',
1454 1206: 'error loading version info',
1455 1207: 'error loading phone state',
1456 1209: 'error loading user state',
1457 1210: 'error loading user info',
1458 1211: 'login failure',
1459 1212: 'error connect using session',
1460 1213: 'no password or session',
1461 1214: 'max online users count reached, license limitation',
1462 1215: 'oktell service is not available',
1463 // call
1464 2001: 'user state - disconnected',
1465 2002: 'phone not connected',
1466 2101: 'user has hold call and is talking now',
1467 2102: 'user in conference now',
1468 2103: 'phone state not valid for call',
1469 2104: 'user state - busy',
1470 2105: 'calling number is talking with us',
1471 2106: 'bad number',
1472 2107: 'error autocall method call',
1473 2108: 'error user or phone state for call',
1474 // conference
1475 2201: 'no numbers to invite',
1476 2202: 'cant build conference from current call',
1477 2203: 'no number to create conference',
1478 2204: 'error conference method call',
1479 2205: 'bad user or phone state for creating conference',
1480 2206: 'cant invite hold abonent',
1481 2207: 'error inviting',
1482 2208: 'cant create conference while in callcenter in break',
1483 // transfer
1484 2301: 'error transfer method call',
1485 2302: 'bad user or phone state for transfer',
1486 2303: 'nothing to transfer',
1487 2304: 'bad number for transfer',
1488 // toggle
1489 2401: 'error toggle method executing',
1490 2402: 'nothing to toggle, no hold',
1491 // ghost modes
1492 2501: 'not in conference',
1493 2502: 'server retunred error while enabling ghost mode',
1494 2503: 'bad ghost mode',
1495 2504: 'bad userId or number',
1496 2505: 'error rigths',
1497 2506: 'user is not in ghost mode',
1498 2507: 'cant change ghost mode of this user',
1499 // flash
1500 2601: 'bad flash mode',
1501 2602: 'error while exec flash method',
1502 // queue
1503 2701: 'error while loading user queue',
1504 // change pass
1505 2801: 'wrong old password',
1506 2802: 'incorrect new password',
1507 2803: 'error while exec changepassword method on server',
1508 // answer
1509 2901: 'incorrect state',
1510 2902: 'phone probably does not support intercom calls',
1511 // uploadFile
1512 3001: 'error while getting temp pass',
1513 3002: 'aborted in beforeRequest callback function'
1514
1515 };
1516
1517 /**
1518 * Return error object
1519 * @param code from errorTypes
1520 * @param msg that will be added to errorMessage
1521 * @param obj that will extend return object
1522 * @return {*} error object
1523 */
1524 var getErrorObj = function( code , msg, obj ) {
1525 code = parseInt(code);
1526
1527 var errorObj = extend( obj || {},{
1528 result: false,
1529 errorCode: code,
1530 errorMessage: (errorTypes[code] ? errorTypes[code] : '' ) + ( msg ? msg.toString() : '' )
1531 });
1532 log ('ERROR ' + code + ' ' + errorObj.errorMessage, errorObj );
1533 return errorObj;
1534 };
1535
1536 /**
1537 * Return success object
1538 * @param obj that will extend return object
1539 * @return {*}
1540 */
1541 var getSuccessObj = function(obj) {
1542 var sObj = extend( obj || {}, {result:true});
1543 log('SUCCESS ', sObj)
1544 return sObj;
1545 };
1546
1547 /**
1548 * Return object, that explain result of operation, error object or succec object
1549 * @param result - if true than return success object, else return error object
1550 * @param obj that will extend return object
1551 * @param errorCode error code from errorTypes
1552 * @param msg that concatenated to returning message
1553 * @return {*}
1554 */
1555 var getReturnObj = function( result, obj, errorCode, msg ) {
1556 if ( result ) {
1557 return getSuccessObj(obj);
1558 } else {
1559 return getErrorObj(errorCode, msg, obj);
1560 }
1561 };
1562
1563 var bindOktellEvent = function(eventNames, callback) {
1564 eventNames = normalizeEventNames(eventNames);
1565 evObjs = [];
1566 for (var i = 0; i < eventNames.length; i++) {
1567 var event = eventNames[i];
1568 var alreadyExist = false;
1569 for (var j = 0; j < nativeEventsForBindAfterConnect.length; j++) {
1570 var obj = nativeEventsForBindAfterConnect[j];
1571 if ( obj && obj.eventName == event && obj.callback === callback ) {
1572 alreadyExist = true;
1573 break;
1574 }
1575 }
1576 if ( alreadyExist ) {
1577 eventNames[i] = undefined;
1578 } else {
1579 var evObj = {eventName:event, callback: callback};
1580 nativeEventsForBindAfterConnect.push(evObj);
1581 evObjs.push(evObj);
1582 }
1583 }
1584 if ( oktellConnected() ) {
1585 for (var i = 0; i < evObjs.length; i++) {
1586 evObjs[i].binded = true;
1587 }
1588 server.bindOktellEvent( eventNames, callback );
1589 }
1590 }
1591
1592 var unbindOktellEvent = function(eventNames, callback) {
1593 if ( ! eventNames ) {
1594 nativeEventsForBindAfterConnect = [];
1595 } else {
1596 eventNames = normalizeEventNames(eventNames);
1597 if ( ! eventNames ) { return false; }
1598 callback = typeof callback == 'function' ? callback : false;
1599
1600 for (var i = 0; i < eventNames.length; i++) {
1601 var event = eventNames[i];
1602 for (var j = 0; j < nativeEventsForBindAfterConnect.length; j++) {
1603 var evObj = nativeEventsForBindAfterConnect[j];
1604 if ( evObj && evObj.eventName == event && ( ( callback && evObj.callback === callback ) || ! callback ) ) {
1605 nativeEventsForBindAfterConnect[j] = undefined;
1606 }
1607 }
1608 }
1609 }
1610 if ( server ) {
1611 server.unbindOktellEvent(eventNames, callback);
1612 }
1613 }
1614
1615 /**
1616 * Wrapper for server.sendOktell with userlogin setting
1617 * @param method name from Oktell Websocket API
1618 * @param params for method
1619 * @param callback on oktell server answer
1620 */
1621 var sendOktell = function(method, params, callback) {
1622 var callbackFn = typeof params == 'function' ? params : callback
1623 if ( serverConnected() ) {
1624 if ( isValidMethodVersion(method) ) {
1625 params = size(params) ? params : {};
1626 var params = extend({ userlogin: oktellInfo.login }, params );
1627 var errorTimer;
1628 if ( typeof callbackFn == 'function' ) {
1629 var errorTimer = setTimeout(function() {
1630 log('error timer for method ' + method);
1631 callFunc(callbackFn,getErrorObj(1102, ': ' + method));
1632 }, oktellOptions.queryTimeout);
1633 }
1634 server.sendOktell(method, params, function(data) {
1635 clearTimeout(errorTimer);
1636 log('<<<< ' + method, data);
1637 callFunc(callbackFn,data);
1638 });
1639 log('>>>> ' + method, params);
1640
1641 } else {
1642 callFunc(callbackFn,getErrorObj(1101, ' ' +method));
1643 if ( methodVersions[method].critical ) {
1644 disconnect( getDisconnectReasonObj(10), method );
1645 }
1646 }
1647 } else {
1648 callFunc(callbackFn,getErrorObj(1201));
1649 }
1650 };
1651
1652 /**
1653 * Call oktell websocket API method, that not return anything. sendOktell wrapper
1654 * @param method name
1655 * @param params for method
1656 */
1657 var sendOktellWithoutBackData = function( method, params ) {
1658 if ( ! serverConnected() ) {
1659 return getErrorObj(1201);
1660 } else if ( ! isValidMethodVersion(method) ) {
1661 return getErrorObj(1101, ' ' + method);
1662 } else {
1663 sendOktell(method, params, null, true);
1664 return getSuccessObj();
1665 }
1666 };
1667
1668 /**
1669 * execute websocket api method or permitted stored procedure on oktell server's db
1670 * @param method or procedure name
1671 * @param params
1672 * @param callback
1673 */
1674 var exec = function(method, params, callback ) {
1675 var callbackFn = typeof params == 'function' ? params : callback;
1676 if ( ! method ) {
1677 callFunc(callbackFn,getErrorObj(1104));
1678 } else {
1679 if ( oktellInfo.allowedProcedures[method.toLowerCase()] ) {
1680 var p = {
1681 userid: oktellInfo.userid,
1682 userlogin: oktellInfo.login,
1683 inputparams: params || {}
1684 };
1685 log('>>>> ' + method, p);
1686 server.execProc(method, p, function(items, datasetRaw) {
1687 var resultdata = {
1688 result: false
1689 };
1690 if ( items ) {
1691 resultdata.result = true;
1692 resultdata.datasets = items;
1693 resultdata.datasetsRaw = datasetRaw;
1694 }
1695 log('<<<< ' + method, resultdata);
1696 callFunc(callbackFn, getReturnObj(resultdata.result, resultdata, 1105, ' ' + method));
1697 });
1698 } else {
1699 if ( ! callbackFn ) {
1700 sendOktell(method,params);
1701 } else {
1702 sendOktell(method,params,function(data) {
1703 var r = data.errorCode ? getReturnObj(data.result,data, data.errorCode) : getReturnObj(data.result,data, 1103, ' ' + method);
1704 callFunc(callbackFn, r);
1705 });
1706 }
1707 }
1708 }
1709 };
1710 exportApi('exec', exec);
1711
1712 /**
1713 * Custom user events stuff
1714 * @type {*}
1715 */
1716 var customEvents = extend({
1717 /**
1718 * Subscribe to all custom event on server
1719 * @return {Boolean}
1720 */
1721 sendCustomBinding: function() {
1722 if ( this._subscribed ) {
1723 return false;
1724 }
1725 this._subscribed = true;
1726 var that = this;
1727 server.bindOktellEvent('customevent', function(data) {
1728 if ( data && data.eventname ) {
1729 that.trigger( data.eventname, data.eventparam );
1730 }
1731 });
1732 },
1733 /**
1734 * Trigger custom event through oktell server
1735 * @param eventName
1736 * @param recipients userid's array
1737 * @param data to send with event
1738 * @param send back event or not, used only if recipients array defined
1739 */
1740 triggerCustomEvent: function( eventName, recipientsArr, data, sendBack ) {
1741 sendOktell( 'triggercustomevent', {
1742 userid: oktellInfo.userid,
1743 userlogin: oktellInfo.login,
1744 eventname: eventName,
1745 eventparam: data,
1746 recipients: recipientsArr,
1747 sendback: sendBack ? 1 : "0"
1748 });
1749 }
1750 },Events);
1751 exportApi('triggerCustomEvent',customEvents.triggerCustomEvent, customEvents);
1752 exportApi('offCustomEvent',customEvents.off, customEvents);
1753 exportApi('onCustomEvent',customEvents.on, customEvents);
1754
1755 /**
1756 * Load users
1757 * @param callback
1758 */
1759 var loadUsers = function(callback) {
1760 sendOktell('getallusernumbers', { fillsubordinates: true }, function(data) {
1761 if ( data.result && data.users ) {
1762 each(data.users, function(u) {
1763 users[ u.id ] = {
1764 id: u.id,
1765 name: u.name,
1766 number: u.main || undefined,
1767 numbers: u.nums || [],
1768 //controlMe: u.controlMe ? true : false,
1769 controlledByMe: u.sub ? true : false
1770 };
1771 users[ u.id ].numberObj = numbers[ users[ u.id ].number ] || undefined;
1772 if ( users[ u.id ].numberObj ) {
1773 users[ u.id ].numberObj.userid = u.id;
1774 users[ u.id ].numberObj.userObj = users[ u.id ];
1775 }
1776 });
1777 sendOktell("getalluserphotolink", {mode: "page"}, function(data) {
1778 if ( data.result ) {
1779 var servPath = getWebServerLink();
1780 each(data.links, function(data) {
1781 var user = data.id == oktellInfo.userid ? oktellInfo : users[data.id];
1782 if ( user ){
1783 user['avatarLink'] = data['link'] ? servPath + data['link32x32'] : oktellOptions.defaultAvatar || '';
1784 user['avatarLink32x32'] = data['link32x32'] ? servPath + data['link32x32'] : oktellOptions.defaultAvatar32x32 || '';
1785 user['avatarLink96x96'] = data['link96x96'] ? servPath + data['link96x96'] : oktellOptions.defaultAvatar64x64 || '';
1786 }
1787 });
1788 }
1789
1790 callFunc(callback);
1791 });
1792 } else {
1793 callFunc(callback);
1794 }
1795 });
1796 };
1797
1798 /**
1799 * Is target user is controlled by me
1800 * @param target
1801 * @return {*}
1802 */
1803 var userControlledByMe = function( target ) {
1804 if ( ! target ){
1805 return false;
1806 } else if ( (target = target.toString()) && users[target] && users[target].id ) {
1807 return users[target].controlledByMe;
1808 } else if ( numbers[target] && numbers[target].userObj ) {
1809 return numbers[target].userObj.controlledByMe;
1810 } else {
1811 return false;
1812 }
1813 };
1814
1815 /**
1816 * Load number plan
1817 * @param callback
1818 */
1819 var loadPbxNumbers = function(callback) {
1820 sendOktell('getpbxnumbers', {mode:'full'}, function(data) {
1821 if ( data.result && data.numbers ) {
1822 each(data.numbers, function(n) {
1823 numbers[ n.number ] = n;
1824 numbersById[ n.id ] = numbers[ n.number ];
1825 });
1826 }
1827 callFunc(callback);
1828 });
1829 };
1830
1831 /**
1832 * Return url of oktell web server
1833 * @return {*}
1834 */
1835 var getWebServerLink = function() {
1836 if ( oktellInfo.currentUrl && oktellInfo.oktellWebServerPort ) {
1837 var protocol = oktellInfo.currentUrl.match(/^wss/) ? "https://" : "http://",
1838 host = oktellInfo.currentUrl.match(/wss?:\/\/([^\s\/:]+)/)[1];
1839 port = '';
1840 if ( ( protocol == 'https://' && self.getMyInfo().oktellWebServerPort != '443' ) || ( protocol == 'http://' && self.getMyInfo().oktellWebServerPort != '80' ) ) {
1841 port = ':' + self.getMyInfo().oktellWebServerPort;
1842 }
1843 return protocol + host + port;
1844 }
1845 return false;
1846 };
1847
1848 /**
1849 * Set callback for http query
1850 * @param pass
1851 * @param onResultsEvent
1852 */
1853 var setHttpQueryCallback = function( pass, callback ) {
1854 var self = this;
1855 if ( pass ) {
1856 httpQueryData[pass] = {
1857 time: (new Date()).getTime(),
1858 callback: callback
1859 }
1860 }
1861 }
1862 //exportApi('setHttpQueryCallback',setHttpQueryCallback);
1863
1864 /**
1865 * Get password for http query
1866 * @param callback
1867 */
1868 var getHttpQueryPass = function( responsetowebsock, callback) {
1869 sendOktell('gettemphttppass', {responsetowebsock: responsetowebsock ? true : false}, function(data) {
1870 if ( data.result ) {
1871 callFunc(callback, getSuccessObj(data))
1872 } else {
1873 callFunc(callback, getErrorObj(1103, ' gettemphttppass', data))
1874 }
1875 });
1876 }
1877 //exportApi('getHttpQueryPass',getHttpQueryPass);
1878
1879 /**
1880 * Set up user avatar
1881 * @param filepath
1882 * @param callback
1883 */
1884 var setUserAvatar = function( filepath, callback ) {
1885 if (! filepath) { return ;}
1886
1887 var t = filepath.toString().split('.');
1888 if ( t.length < 2 || ['jpg','gif','png','jpeg'].indexOf(t[t.length-1]) == -1 ) {
1889 return;
1890 }
1891
1892 sendOktell('setmyuserphoto', {filepath: filepath}, function(data) {
1893 callFunc(callback, getReturnObj(data.result, {},1103,' setmyuserphoto'));
1894 });
1895 };
1896 exportApi('setUserAvatar', setUserAvatar);
1897
1898 /**
1899 * Load my avatar
1900 * @param callback
1901 */
1902 var loadUserAvatar = function(callback) {
1903 var self = this;
1904 sendOktell('getuserphoto', {mode: 'page'}, function(data) {
1905 if ( data.result ) {
1906 var servPath = getWebServerLink();
1907 oktellInfo['avatarLink'] = data['link'] ? servPath + data['link32x32'] : oktellOptions.defaultAvatar || '';
1908 oktellInfo['avatarLink32x32'] = data['link32x32'] ? servPath + data['link32x32'] : oktellOptions.defaultAvatar32x32 || '';
1909 oktellInfo['avatarLink96x96'] = data['link96x96'] ? servPath + data['link96x96'] : oktellOptions.defaultAvatar64x64 || '';
1910
1911 callFunc(callback, getSuccessObj({
1912 avatarLink: oktellInfo['avatarLink'], avatarLink32x32: oktellInfo['avatarLink32x32'], avatarLink96x96: oktellInfo['avatarLink96x96']
1913 }));
1914 } else {
1915 callFunc(callback, getErrorObj(1103, ' getuserphoto'));
1916 }
1917 });
1918 };
1919 exportApi('getUserAvatar',loadUserAvatar);
1920
1921 /**
1922 * Upload file to Oktell webserver. jQuery used if exist, else pure javascript version called
1923 * @param storagemode - storage, temp, script or scriptplain
1924 * @param pathmode - absolute or relative
1925 * @param callback
1926 * @return
1927 */
1928 var uploadFile = function( options, callback, beforeRequest) {
1929 var $ = window.$ || window.jQuery || undefined;
1930 if ( ! $ ) {
1931 return uploadFilePure.apply(self, arguments);
1932 }
1933
1934 var accept = options.accept;
1935 delete options.accept;
1936 if ( accept ) {
1937 if ( ! isArray(accept) ) {
1938 accept = [accept];
1939 }
1940 accept = 'accept="' + accept.join(',') + '"';
1941 } else {
1942 accept = '';
1943 }
1944
1945 var rid = Math.random().toString().replace('.',''),
1946 frameId = '_oktelljs_user_avatar_frame_' + rid,
1947 formId = '_oktelljs_user_avatar_form_' + rid,
1948 inputId = '_oktelljs_user_profile_select_file_' + rid;
1949
1950 $('body').append('<iframe width="0" height="0" id="'+frameId+'" name="'+frameId+'"></iframe>');
1951 $('body').append('<form enctype="multipart/form-data" target="'+frameId+'" id="'+formId+'" action="" method="post">' +
1952 '<input style="visibility: hidden;" type="file" ' + accept + ' name="file" id="'+inputId+'" /></form>');
1953
1954 var callCallback = function(data) {
1955 $('#'+formId).remove();
1956 $('#'+frameId).remove();
1957 callFunc(callback, data);
1958 }
1959
1960 $('#'+inputId).change(function(e) {
1961
1962 var file = $(e.currentTarget).val();
1963
1964 if ( ! file ) {
1965 return;
1966 }
1967
1968 var fileName = file.replace('/', '\\').split('\\');
1969 fileName = fileName[fileName.length-1];
1970
1971 if ( typeof beforeRequest == 'function' && beforeRequest(getSuccessObj({fileName:fileName})) === false ) {
1972 callCallback(getErrorObj(3002));
1973 return;
1974 }
1975
1976 getHttpQueryPass( true, function(data) {
1977
1978 if ( data.result ) {
1979
1980 $("#"+formId).attr("action", getWebServerLink() + "/upload?temppass="+ data.password + buildParams(options) );
1981
1982 setHttpQueryCallback( data.password, function(data) {
1983 var r = /uploadfilesresult count="1"[\s\S]+?path="([\s\S]+?)"/,
1984 path = r.exec(data);
1985
1986 if ( !path || ! path[1] ) {
1987 return false
1988 }
1989
1990 path = path[1].replace( /\\/g , '/');
1991
1992 callCallback(getSuccessObj({path:path}));
1993 });
1994
1995 $('#'+formId).submit()
1996 } else {
1997 callCallback(getErrorObj(3001));
1998 }
1999
2000 });
2001 });
2002
2003
2004 $('#'+inputId).click()
2005
2006
2007 };
2008
2009 /**
2010 * Upload file to Oktell webserver. Pure javascript version
2011 * @param storagemode - storage, temp, script or scriptplain
2012 * @param pathmode - absolute or relative
2013 * @param callback
2014 * @return
2015 */
2016 var uploadFilePure = function( options, callback) {
2017 var rid = Math.random().toString().replace('.',''),
2018 frameId = '_oktelljs_user_avatar_frame_' + rid,
2019 formId = '_oktelljs_user_avatar_form_' + rid,
2020 inputId = '_oktelljs_user_profile_select_file_' + rid;
2021
2022 var accept = options.accept;
2023 delete options.accept;
2024 if ( accept ) {
2025 if ( ! isArray(accept) ) {
2026 accept = [accept];
2027 }
2028 accept = 'accept="' + accept.join(',') + '"';
2029 } else {
2030 accept = '';
2031 }
2032
2033 var iframe = document.createElement('iframe');
2034 iframe.id = frameId;
2035 iframe.name = frameId;
2036 iframe.width = 0;
2037 iframe.height = 0;
2038 document.body.appendChild(iframe);
2039
2040 var form = document.createElement('form');
2041 form.id = formId;
2042 form.style.display = 'none';
2043 form.target = frameId;
2044 form.enctype = "multipart/form-data";
2045 form.action = '';
2046 form.method = 'post';
2047 document.body.appendChild(form);
2048
2049 var input = document.createElement('input');
2050 input.style.visibility = 'hidden';
2051 input.type = 'file';
2052 input.id = inputId
2053 input.name = 'file';
2054 input.accept = accept;
2055 form.appendChild(input);
2056
2057 var callCallback = function(data) {
2058 var elem;
2059 (elem=document.getElementById(frameId)).parentNode.removeChild(elem);
2060 (elem=document.getElementById(formId)).parentNode.removeChild(elem);
2061 callFunc(callback, data);
2062 }
2063
2064
2065 input.onchange = function() {
2066 var file = input.value;
2067
2068 if ( ! file ) {
2069 return;
2070 }
2071
2072 var fileName = file.replace('\\', '/').split('/');
2073 fileName = fileName[fileName.length-1];
2074
2075 if ( typeof beforeRequest == 'function' && beforeRequest(getSuccessObj({fileName:fileName})) === false ) {
2076 callCallback(getErrorObj(3002));
2077 return;
2078 }
2079
2080 getHttpQueryPass( true, function(data) {
2081 if ( data.result ) {
2082 form.action = getWebServerLink() + "/upload?temppass="+ data.password + '&' + buildParams(options);
2083
2084 setHttpQueryCallback( data.password, function(data) {
2085 var r = /uploadfilesresult count="1"[\s\S]+?path="([\s\S]+?)"/,
2086 path = r.exec(data);
2087
2088 if ( !path || ! path[1] ) {
2089 return false
2090 }
2091
2092 path = path[1].replace( /\\/g , '/');
2093
2094 callCallback(getSuccessObj({path:path}));
2095 });
2096
2097 form.submit();
2098 } else {
2099 callCallback(getErrorObj(3001));
2100 }
2101 });
2102 }
2103
2104 input.click();
2105
2106 };
2107 exportApi('uploadFile', uploadFile);
2108
2109 var DynamicMethods = (function() {
2110 function DynamicMethods(oktell, server){
2111 var self = this;
2112 self.oktell = oktell;
2113 self.server = server;
2114 self.currentMethods = {};
2115 self.methodTimers = {};
2116 self.onExecuteMethod = function(data) {
2117 if ( ! data.executionid ) {
2118 return false;
2119 }
2120 self.currentMethods[data.executionid] = true;
2121 oktell.trigger('')
2122 };
2123 self.onCancelMethod = function(data) {
2124 if ( ! data.executionid ) {
2125 return false;
2126 }
2127 delete self.currentMethods[data.executionid];
2128 };
2129 self.onExecuteMethodWaitAborted = function(data) {
2130 if ( ! data.executionid ) {
2131 return false;
2132 }
2133 self.currentMethods[data.executionid] = true;
2134 self.methodTimers[data.executionid] = setTimeout(function() {
2135 delete self.currentMethods[data.executionid];
2136 }, data.waitresponsems );
2137 };
2138 };
2139 DynamicMethods.prototype.init = function(server) {
2140 var self = this;
2141 self.server.bindOktellEvent('dynamic', function() {});
2142 self.server.bindOktellEvent('dynamicwaitabort', function() {});
2143 self.server.bindOktellEvent('executemethod', self.onExecuteMethod, self);
2144 self.server.bindOktellEvent('cancelmethod', self.onCancelMethod, self);
2145 self.server.bindOktellEvent('executemethodwaitaborted', self.onExecuteMethodWaitAborted, self);
2146 }
2147 DynamicMethods.prototype.sendMethodResult = function(executionId, data) {
2148 var self = this;
2149 if ( self.currentMethods[executionId] ) {
2150 delete self.currentMethods[executionId];
2151 sendOktell('methodresult', {executionid: executionId, outputparameters: data || {}});
2152 } else {
2153 return false;
2154 }
2155 }
2156 DynamicMethods.prototype.reset = function() {
2157 var self = this;
2158 self.currentMethods = {};
2159 for ( var id in self.methodTimers ) {
2160 if ( self.methodTimers.hasOwnProperty(id) ) {
2161 clearTimeout(self.methodTimers[id]);
2162 }
2163 }
2164 self.server.unbindOktellEvent('executemethod', self.onExecuteMethod);
2165 self.server.unbindOktellEvent('cancelmethod', self.onCancelMethod);
2166 self.server.unbindOktellEvent('executemethodwaitaborted', self.onExecuteMethodWaitAborted);
2167
2168 }
2169 return DynamicMethods;
2170 })();
2171 extend(DynamicMethods.prototype, Events);
2172 // TODO bindOktell or self.server.bindOktellEvent ?
2173 var dynamicMethods = new DynamicMethods()
2174
2175
2176
2177 /**
2178 * USER STATES
2179 * @type {Object}
2180 */
2181 var userStates = extend({},Events,{
2182 _stateId: 0,
2183 states: {
2184 DISCONNECTED: 0,
2185 READY: 1,
2186 BREAK: 2,
2187 OFF: 3,
2188 BUSY: 5,
2189 RESERVED: 6,
2190 NOPHONE: 7
2191 },
2192 webStates: {
2193 READY: 1, //'Ready for calls',
2194 DND: 2, //'DND',
2195 REDIRECT: 3, //'Redirect', not in callcenter
2196 BREAK: 4, // break, only in callcenter
2197 BUSY: 5,
2198 RESERVED: 6,
2199 NOPHONE: 7
2200 },
2201 onCallCenter: 0,
2202 _onRedirect: false,
2203 _status: 0,
2204 _webStateId: 0,
2205 onBreak: 0,
2206 breakReasons: {},
2207
2208 loadBreakReasons: function(callback) {
2209 var that = this;
2210 sendOktell('cc_getlunchtypes', {}, function(data) {
2211 if ( data.result ) {
2212 each( data.items, function(r) {
2213 that.breakReasons[r.id.toString()] = r;
2214 });
2215
2216 }
2217 callFunc(callback, getReturnObj(data.result, data, 1103, ' cc_getlunchtypes') );
2218 });
2219 },
2220
2221 /**
2222 * String name for state
2223 * @param code
2224 * @return {*}
2225 */
2226 getStateStr: function( code ) {
2227 return getStateByCode( code === undefined ? this._stateId : parseInt(code), this.states );
2228 },
2229
2230 /**
2231 * String name for web state
2232 * @param code
2233 * @return {*}
2234 */
2235 getWebStateStr: function( code ) {
2236 return getStateByCode( code === undefined ? this._webStateId : parseInt(code), this.webStates );
2237 },
2238
2239 /**
2240 * ######### ######### # ######### ########## ###### #########
2241 * Get or set current state
2242 * @param newStateId
2243 * @return {Number} current stateId
2244 */
2245 state: function( newStateId ) {
2246 newStateId = parseInt(newStateId);
2247 if ( this.getStateStr(newStateId) && this._stateId !== newStateId ) {
2248 log('SET USER STATE ' + newStateId + ' ' + this.getStateStr(newStateId) );
2249 this._stateId = newStateId;
2250 this.trigger('userStateChange', this._stateId);
2251 }
2252 return this._stateId;
2253 },
2254
2255 /**
2256 * Change states through change stateid on server or enabling redirect on server. Also save local states
2257 * @param newWebState
2258 * @param silent - if true, then event statusChange API event
2259 * @param message - lunch reason message in callcenter
2260 * @return {Boolean}
2261 */
2262 changeStates: function( newWebState, silent, message ) {
2263 newWebState = this.webStates[newWebState.toString().toUpperCase()] || parseInt(newWebState);
2264
2265 if ( ! this.getWebStateStr(newWebState) ) { return false; }
2266
2267 if ( ( newWebState == this._webStateId && ! this.setAfterBusy ) || ! serverConnected() ) { return false; }
2268 var userState = this.state();
2269// // set state, that was set while user was busy
2270// if ( userState == this.states.BUSY && this.setAfterBusy && this.setAfterBusy != newWebState ) {
2271// newWebState = this.setAfterBusy;
2272// this.setAfterBusy = false;
2273// }
2274
2275 switch(newWebState) {
2276 case 1:
2277 if ( userState == this.states.BUSY ) {
2278
2279 this.setAfterBusy = this.webStates.READY;
2280 sendOktell('setuserstate', {userstateid: 1});
2281 } else {
2282 sendOktell('setuserstate', {userstateid: 1});
2283 }
2284 break;
2285 case 2:
2286 if ( userState == this.states.BUSY ) {
2287 this.setAfterBusy = this.webStates.DND;
2288 } else {
2289 if ( userState == this.states.READY || userState == this.states.BREAK || userState == this.states.OFF ) {
2290 sendOktell('setuserstate', {userstateid: 3} );
2291 }
2292 }
2293 break;
2294 case 3:
2295 if ( this.getRedirectNumber() ) {
2296 this.enableUserRedirectState( true );
2297 } else {
2298 return false;
2299 }
2300 break;
2301 case 4:
2302 if ( this.onCallCenter ) { //&& ( userState == this.states.READY || userState == this.states.BREAK || userState == this.states.OFF ) ) {
2303 var sObj = {userstateid: 2}, msg = '';
2304 if ( message ) {
2305 if ( this.breakReasons[message] ) {
2306 sObj.lunchreasonid = message;
2307 } else {
2308 sObj.lunchreasonmsg = message;
2309 }
2310 }
2311 sendOktell('setuserstate', sObj );
2312 }
2313 break;
2314 case 5:
2315 if ( userState == this.states.BUSY ) {
2316 this.setAfterBusy = this.webStates.BUSY;
2317 } else {
2318 if ( userState == this.states.READY || userState == this.states.BREAK || userState == this.states.OFF ) {
2319 sendOktell('setuserstate', {userstateid: 5} );
2320 }
2321 }
2322 break;
2323 }
2324
2325 this.webState(newWebState, silent);
2326 return true;
2327 },
2328
2329 /**
2330 * Save stateId local
2331 * @param newStateId
2332 * @param newStateId
2333 * @param silent silent - if true, then event statusChange API event
2334 * @return {Number}
2335 */
2336 webState: function( newStateId, silent ) {
2337 if ( newStateId !== undefined && this.getWebStateStr(newStateId) && this._webStateId != newStateId ) {
2338 log('SET WEB STATE ' + this.getWebStateStr(newStateId));
2339 var oldStatus = this.getWebStateStr(this._webStateId);
2340 this._webStateId = newStateId;
2341 if ( ! silent ) {
2342 self.trigger('statusChange', this.getWebStateStr(this._webStateId), oldStatus );
2343 }
2344 }
2345 return this._webStateId;
2346 },
2347
2348 /**
2349 * Get redirect state or save redirect state locally
2350 * @param newState ##### ######### #############
2351 * @return {Boolean} ####### ######### #############
2352 */
2353 onRedirect: function(newState) {
2354 if ( newState !== undefined ) {
2355 newState = newState ? true : false;
2356 if ( this._onRedirect !== newState) {
2357 this._onRedirect = newState;
2358 events.trigger('userOnRedirectChanged', this._onRedirect);
2359 }
2360 }
2361 return this._onRedirect;
2362 },
2363
2364 /**
2365 * Load all states from server
2366 */
2367 loadState: function(callback) {
2368 var that = this;
2369 sendOktell('getuserstate', {}, function(data) {
2370 if ( data.result ) {
2371 that.saveStatesFromServer(data);
2372 }
2373 callFunc(callback, getReturnObj(data.result,data,1103,' getuserstate'));
2374 });
2375 },
2376
2377 callCenterState: function(newState) {
2378 if ( newState !== undefined ) {
2379 newState = newState ? true : false;
2380 if ( this.onCallCenter !== newState ) {
2381 this.onCallCenter = newState;
2382 self.trigger('callCenterStateChange', this.onCallCenter );
2383 }
2384 }
2385 return this.onCallCenter;
2386 },
2387
2388 /**
2389 * Save and set all states locally
2390 * @param data loaded from server {oncallcenter, onlunch, onredirect, userstateid}
2391 */
2392 saveStatesFromServer: function(data) {
2393 this.callCenterState( data.oncallcenter );
2394 this.onBreak = data.onlunch;
2395 this.onRedirect(data.onredirect);
2396
2397 var currentWebState = this.webState();
2398 var currentState = this.state();
2399 this.state( data.userstateid );
2400 if ( currentWebState == this.webStates.DND && this.setAfterBusy == this.webStates.DND && currentState == 5 && data.userstateid == 1 ) {
2401 this.setAfterBusy = false;
2402 this.changeStates(this.webStates.DND, true);
2403 return;
2404 }
2405
2406 this.setWebStateFromUserState();
2407 },
2408
2409 setUserStateBusy: function() {
2410 this.state(5);
2411 },
2412
2413 /**
2414 * Get redirect rule id for redirect state
2415 * @return {String}
2416 */
2417 getUserRedirectId: function() {
2418 return md5( oktellInfo.userid.toLocaleLowerCase() + oktellInfo.userid.toLocaleLowerCase() ).toLowerCase();
2419 },
2420
2421 /**
2422 * Get current redirect number
2423 * @return {*} number or undefined
2424 */
2425 getRedirectNumber: function() {
2426 return oktellInfo.redirectNumber ? oktellInfo.redirectNumber : undefined;
2427 },
2428
2429 /**
2430 * Set redirect number locally
2431 * @param number
2432 * @return {*} object like {number:'564'} or undefined
2433 */
2434 setRedirectNumber: function( number ) {
2435 oktellInfo.redirectNumber = number ? number : undefined;
2436 return oktellInfo.redirectNumber;
2437 },
2438
2439 /**
2440 * Load redirect number from server and set it locally
2441 * @param callback
2442 */
2443 checkUserRedirect: function(callback) {
2444 var that = this;
2445 sendOktell("getredirectrules",{}, function(data) {
2446 if ( data.result ) {
2447 var rule;
2448 if ( data.redirectrules && data.redirectrules.length > 0 ) { // #### #### #######
2449 each( data.redirectrules, function(rule) {
2450 if ( rule.id.replace(/-/g,'').toLowerCase() == that.getUserRedirectId() ) {
2451 that.setRedirectNumber(rule.destinationnumber);
2452 }
2453 });
2454 }
2455 }
2456 callFunc(callback,getReturnObj(data.result,data,1103,' getredirectrules'));
2457 });
2458 },
2459
2460 /**
2461 * Save redirect number
2462 * @param number or empty if need to cancel redirect
2463 * @param callback
2464 */
2465 saveUserRedirect: function(number,callback) {
2466 var that = this;
2467 if ( ! number ) {
2468 sendOktell("deleteredirectrules",{ ids: [ this.getUserRedirectId() ] }, function(data) {
2469 if ( data.result ) {
2470 that.setRedirectNumber(undefined);
2471 if ( that.webState() == that.webStates.REDIRECT ) {
2472 that.changeStates( that.webStates.READY );
2473 }
2474 }
2475 callFunc(callback,getReturnObj(data.result,data,1103,' deleteredirectrules'));
2476 });
2477
2478 } else {
2479 sendOktell("saveredirectrules",{
2480 redirectrule: {
2481 id: that.getUserRedirectId(),
2482 caption: '????????????? ??????????? ?? ???-??????. ????????? ?????????.',
2483 description: '????????????? ??????????? ?? ???-??????. ????????? ?????????.',
2484 priority: 1,
2485 userid: oktellInfo.userid,
2486 isenabled: true,
2487 allowcascade: true,
2488 state: 2,
2489 destinationnumber: number,
2490 onlyforredirectstate: true,
2491 definesources: false
2492 }
2493 }, function(data) {
2494 if ( data.result ) {
2495 that.setRedirectNumber(number);
2496 }
2497 callFunc(callback,getReturnObj(data.result,data,1103,' saveredirectrules'));
2498 });
2499 }
2500 return true;
2501 },
2502
2503 /**
2504 * enable or disable redirect on server
2505 * @param enable
2506 */
2507 enableUserRedirectState: function( enable ) {
2508 sendOktell('setuserstate', { onredirect: enable ? true : false });
2509 },
2510
2511 /**
2512 * Set web state by stateId
2513 */
2514 setWebStateFromUserState: function() {
2515 if ( ! this.onRedirect() ) {
2516 switch ( this.state() ) {
2517 case 1:
2518
2519 this.webState( this.webStates.READY );
2520 break;
2521 case 2:
2522 this.webState( this.webStates.BREAK );
2523 break;
2524 case 3:
2525 this.webState( this.webStates.DND);
2526 break;
2527 /* case 5:
2528 if ( this.onBreak && this.onCallCenter ) {
2529 this.webState( this.webStates.BREAK );
2530 } else {
2531 this.webState( this.webStates.READY );
2532 }
2533 break;*/
2534 case 5:
2535 this.webState( this.webStates.BUSY );
2536 break;
2537 case 7:
2538 this.webState( this.webStates.READY );
2539 break;
2540 }
2541 } else {
2542 this.webState( this.webStates.REDIRECT );
2543 }
2544 }
2545
2546 });
2547 exportApi('setRedirectNumber', userStates.saveUserRedirect, userStates);
2548 exportApi('getStatus', userStates.getWebStateStr, userStates);
2549 exportApi('setStatus', userStates.changeStates, userStates);
2550 exportApi('setUserStateBusy', userStates.setUserStateBusy, userStates);
2551
2552 /**
2553 * PHONE
2554 * @type {Object}
2555 */
2556 var phone = {
2557
2558 _conferenceInfo: {},
2559
2560 // from this version oktell has 'number' param for 'createconference' method for
2561 // all phone numbers, server decides, is it external or internal
2562 _oktellDatedWithConfNumber: 140929,
2563
2564 _holdNumber: false,
2565 _conferenceId: false,
2566 abonentList: {},
2567 queueList: {},
2568 answerCheckTimeout: 3000,
2569 _talkLength: 0,
2570 _talkTimer: false,
2571 sip: false,
2572 sipActive: false,
2573 sipHasRTCSession: false,
2574 _notRoutingIvrState: false,
2575 currentSessionData: {},
2576 intercomSupport: null,
2577 states: {
2578 DISCONNECTED: -1,
2579 READY: 0,
2580 BACKCALL: 1,
2581 CALL: 2,
2582 RING: 3,
2583 BACKRING: 4,
2584 TALK: 5
2585 //CALLWEBPHONE: 6
2586 },
2587
2588
2589 setSipPhone: function(sip) {
2590 var that = this;
2591 that.sip = sip;
2592 that.sip.on('connect', function() {
2593 that.sipActive = true;
2594 });
2595 that.sip.on('disconnect', function() {
2596 that.sipHasRTCSession = false;
2597 that.sipActive = false;
2598 });
2599 that.sip.on('ringStart', function( name, remoteIdentity) {
2600 self.trigger('webrtcRingStart', name, remoteIdentity);
2601 });
2602 that.sip.on('RTCSessionFailed', function() {
2603
2604 });
2605 that.sip.on('RTCSessionStarted', function() {
2606 that.sipHasRTCSession = true;
2607 self.trigger('')
2608// that.loadStates();
2609 });
2610 that.sip.on('RTCSessionEnded', function() {
2611 that.sipHasRTCSession = false;
2612 that.loadStates();
2613 });
2614 that.sip.on('RTCSessionFailed', function() {
2615 that.sipHasRTCSession = false;
2616 });
2617 that.sip.on('sessionClose', function() {
2618 that.sipHasRTCSession = false;
2619 that.loadStates();
2620 });
2621
2622 },
2623
2624 notRoutingIvrState: function(state) {
2625 if ( typeof state !== "undefined" && Boolean(state) !== this._notRoutingIvrState ){
2626 this._notRoutingIvrState = Boolean(state);
2627 }
2628 return this._notRoutingIvrState;
2629 },
2630
2631 answer: function(callback) {
2632 var self = this,
2633 checkInterval,
2634 checkIntercomSupport,
2635 afterTimer,
2636 isAnswerSuccess;
2637
2638 if ( self.sipActive ) {
2639 self.sip.answer();
2640 callFunc(callback, getSuccessObj()); // TODO check answer result for callback
2641 } else if ( self.intercomSupport === false ) {
2642 callFunc(callback, getErrorObj(2902));
2643 } else if ( self.state() == self.states.RING || self.state() == self.states.BACKRING ) {
2644 sendOktell('pbxanswercall');
2645 afterTimer = function() {
2646 clearInterval(checkInterval);
2647 clearTimeout(checkTimer);
2648 callFunc(callback, getReturnObj(self.intercomSupport, {}, 2902));
2649 }
2650 checkIntercomSupport = function() {
2651 //TODO #CC-1216 ######## ########## Oktell.js ##### ###########
2652 //return self.intercomSupport = ( self.state() == self.states.TALK || self.state() == self.states.CALL );
2653 return self.intercomSupport = true;
2654 }
2655 checkInterval = setInterval(function() {
2656 if ( checkIntercomSupport() ) {
2657 afterTimer();
2658 }
2659 }, 50);
2660 checkTimer = setTimeout(function() {
2661 afterTimer();
2662 }, self.answerCheckTimeout);
2663 } else {
2664 callFunc(callback, getErrorObj(2901));
2665 }
2666 },
2667
2668 /**
2669 * Set info about conference
2670 * @param newInfoObj
2671 */
2672 setConferenceInfo: function( newInfoObj ) {
2673 this._conferenceInfo = typeof newInfoObj == 'object' ? newInfoObj : {};
2674 },
2675
2676 /**
2677 * Get info about conference
2678 * @return {*|Object}
2679 */
2680 getConferenceInfo: function() {
2681 return this._conferenceInfo || {};
2682 },
2683
2684 /**
2685 * Clear hold info
2686 * @return {Boolean}
2687 */
2688 clearHold: function() {
2689 this.setHold(false);
2690 return true;
2691 },
2692 /**
2693 * Set hold info
2694 * @param info - phone number or conference id
2695 * @return {Boolean} #####
2696 */
2697 setHold: function( info ) {
2698 var oldHoldInfo = this.getHoldInfo();
2699 if ( info !== undefined && ( ( info.userid && info.userid != this._holdNumber ) || ( info.number && info.number != this._holdNumber ) || ( info.conferenceid && info.conferenceid != this._holdNumber ) ) ) {
2700
2701 var oldHoldAbonent = this._holdAbonent;
2702
2703 this._holdNumber = info.conferenceid ? info.conferenceid : ( info.userid ? info.userid : info.number );
2704 this._holdAbonent = info.conferenceid ? {
2705 isConference : true,
2706 conferenceId: info.conferenceid,
2707 conferenceName: info.conferencename,
2708 conferenceRoom: info.conferenceroom
2709 } : this.createAbonent(info);
2710
2711 var holdAbonentChange = false;
2712 if ( oldHoldAbonent && ( oldHoldAbonent.key != this._holdAbonent.key ) || ( ! this._holdAbonent ) ) {
2713 holdAbonentChange = true;
2714 self.trigger('holdAbonentLeave', cloneObject(oldHoldAbonent) );
2715 }
2716
2717 if ( !(oldHoldAbonent && this._holdAbonent && this._holdAbonent.key && oldHoldAbonent.key && this._holdAbonent.key == oldHoldAbonent.key ) ) {
2718 holdAbonentChange = true;
2719 self.trigger('holdAbonentEnter', cloneObject(this._holdAbonent));
2720 }
2721 var newHoldInfo = this.getHoldInfo();
2722 if ( oldHoldInfo.hasHold != newHoldInfo.hasHold || holdAbonentChange ) {
2723 self.trigger('holdStateChange', cloneObject(newHoldInfo));
2724 }
2725 return true;
2726 } else if ( info === false ) {
2727 if ( this._holdAbonent ) {
2728 self.trigger('holdAbonentLeave', cloneObject(this._holdAbonent));
2729 }
2730 this._holdAbonent = undefined;
2731 var oldHold = this._holdNumber;
2732 this._holdNumber = false;
2733
2734 if ( oldHold !== this._holdNumber ) {
2735 self.trigger('holdStateChange', cloneObject(this.getHoldInfo()));
2736 }
2737 }
2738 return false;
2739 },
2740 /**
2741 * Get hold info
2742 * @return {Object}
2743 */
2744 getHoldInfo: function() {
2745 var i = {
2746 hasHold: this._holdNumber ? true : false
2747 };
2748 if ( i.hasHold ) {
2749 if ( this._holdAbonent && this._holdAbonent.isConference ) {
2750 extend(i,cloneObject(this._holdAbonent));
2751 } else {
2752 i.isConference = false;
2753 i.abonent = cloneObject(this._holdAbonent);
2754 }
2755 }
2756 return i;
2757 },
2758
2759 /**
2760 * Set conference id
2761 * @param newConferenceId
2762 * @param notLoadConfAbonents boolean
2763 * @return {Boolean}
2764 */
2765 conferenceId: function( newConferenceId, notLoadConfAbonents ) {
2766 if ( newConferenceId !== undefined && newConferenceId != this._conferenceId ) {
2767 var oldConfId = this._conferenceId;
2768 this._conferenceId = newConferenceId;
2769 if ( oldConfId ) {
2770 sendOktell('confhandleevent', {
2771 conferenceid: oldConfId,
2772 eventtype: 'competitors',
2773 handle: false
2774 });
2775 }
2776 if ( this._conferenceId ) {
2777
2778 sendOktell('confhandleevent', {
2779 conferenceid: this._conferenceId,
2780 eventtype: 'competitors',
2781 handle: true
2782 });
2783
2784 if ( ! notLoadConfAbonents ) {
2785 this.loadConferenceInfo();
2786 }
2787 } else {
2788 this.setConferenceInfo(false);
2789 }
2790 }
2791 return this._conferenceId;
2792 },
2793 /**
2794 * Set me as conference creator, or get
2795 * @param newState
2796 * @return {*}
2797 */
2798 isConfCreator: function( newState ) {
2799 if ( newState !== undefined ) {
2800 this._isConfCreator = newState ? true : false;
2801 }
2802 return this._isConfCreator;
2803 },
2804
2805 /**
2806 * Return string description of phone state by state code
2807 * @param code , if undefined, current code will be used
2808 * @return {*}
2809 */
2810 getStateStr: function( code ) {
2811 return getStateByCode( code === undefined ? this._stateId : parseInt(code), this.states );
2812 },
2813
2814 /**
2815 * Return string description of phone state for outside api calls. Replace BACKCALL to CALL
2816 * @param code
2817 * @return {*}
2818 */
2819 apiGetStateStr: function(code) {
2820 var state = code === undefined ? this.state() : parseInt(code);
2821 if ( state == this.states.BACKCALL ) {
2822 state = this.states.CALL;
2823 }
2824 return this.getStateStr(state);
2825 },
2826
2827 /**
2828 * Set or get current state
2829 * @param newStateId
2830 * @return {*} current state id
2831 */
2832 state: function( newStateId, oldAbonents, fireEventAnyway ) {
2833 newStateId = parseInt(newStateId);
2834
2835 if ( this.getStateStr(newStateId) && ( fireEventAnyway || newStateId != this._stateId ) ) {
2836
2837 var newState = this.apiGetStateStr(newStateId);
2838 var oldStateId = this._stateId;
2839 var oldState = this.apiGetStateStr(oldStateId);
2840
2841 log('CHANGE STATE FROM ' + this.getStateStr(this._stateId) + ' TO ' + this.getStateStr(newStateId), this.getAbonents(true), oldAbonents);
2842
2843 this._stateId = newStateId;
2844
2845 if ( newStateId === this.states.READY || newStateId === this.states.DISCONNECTED ) {
2846 this.removeAbonents();
2847 this.conferenceId(false);
2848 this.isConfCreator(false);
2849 if ( newStateId === this.states.DISCONNECTED ) {
2850 this.clearHold();
2851 }
2852 }
2853
2854 self.trigger('stateChange', newState, oldState );
2855
2856 var abonents = this.getAbonents(true);
2857 if ( abonents.length == 0 ) {
2858 abonents = oldAbonents;
2859 }
2860
2861
2862 switch ( oldStateId ) {
2863 case this.states.READY: self.trigger('readyStop', oldAbonents); break;
2864 case this.states.RING: self.trigger('ringStop', oldAbonents); break;
2865 case this.states.BACKRING: self.trigger('backRingStop', oldAbonents); break;
2866 case this.states.CALL: self.trigger('callStop', oldAbonents); break;
2867 //case this.states.BACKCALL: self.trigger('callStop', oldAbonents); break;
2868 case this.states.TALK: self.trigger('talkStop', oldAbonents); break;
2869 }
2870
2871 switch ( this._stateId ) {
2872 case this.states.READY: self.trigger('readyStart', abonents); break;
2873 case this.states.RING: self.trigger('ringStart', abonents); break;
2874 case this.states.BACKRING: self.trigger('backRingStart', abonents); break;
2875 case this.states.CALL: self.trigger('callStart',abonents); break;
2876 //case this.states.BACKCALL: self.trigger('callStart', abonents); break;
2877 case this.states.TALK: self.trigger('talkStart', abonents); break;
2878 //case this.states.CALLWEBPHONE: self.trigger('webphoneCallStart', abonents); break;
2879 }
2880
2881
2882 }
2883
2884 return this._stateId;
2885 },
2886
2887 /**
2888 * Load hold state
2889 * @param callback
2890 */
2891 loadFlashInfo: function(callback) {
2892 var that = this;
2893 sendOktell('getflashedabonentinfo', {}, function(data) {
2894 if ( data.result ) {
2895 if ( data.containsflashed && data.abonent ) {
2896 that.setHold( data.abonent );
2897 } else {
2898 that.clearHold();
2899 }
2900 }
2901 callFunc(callback,getReturnObj(data.result,data,1103,' getflashedabonentinfo'));
2902 });
2903 },
2904
2905 /**
2906 * Load phone state
2907 * @param callback
2908 * @params knownData some already known data (for example knownData.isAutoCall, knownData.sequence, etc)
2909 * possible properties for knownData
2910 * isAutoCall: boolean
2911 */
2912 loadStates: function(callback, knownData) {
2913 var that = this;
2914 knownData = knownData || {};
2915 extend(that.currentSessionData, knownData);
2916 //that.loadFlashInfo(function(data) {
2917 if ( ! serverConnected() ) {
2918 return false;
2919 }
2920
2921 sendOktell('getextendedlineinfo', {}, function(data) {
2922 var callCallback = function() {
2923 callFunc(callback,getReturnObj(data.result,data,1103,' getextendedlineinfo'));
2924 }
2925
2926 log('getextendedlineinfo result and that.currentSessionData', data, that.currentSessionData);
2927
2928 if ( data.result ) {
2929
2930 var oldState = that.state();
2931 var oldHoldInfo = that.getHoldInfo();
2932 var oldAbonents = that.getAbonents(true);
2933 var oldAb = oldAbonents && oldAbonents[0] || false;
2934
2935 var setStateFromResultData = function() {
2936 log('setStateFromResultData');
2937
2938 // check if toggle called
2939 var newHoldInfo = that.getHoldInfo();
2940 var newAbonents = that.getAbonents(true);
2941 var newAb = newAbonents && newAbonents[0] || false;
2942
2943 /*if ( newAb && oldAb && oldHoldInfo.hasHold && newHoldInfo.hasHold &&
2944 ( // curr ab is old hold
2945 ( newAb.conferenceId && oldHoldInfo.conferenceId && newAb.conferenceId == oldHoldInfo.conferenceId ) || // curr ab is conf and it is old hold
2946 ( ! newAb.conferenceId && oldHoldInfo.abonent && newAb.key == oldHoldInfo.abonent.key ) // or curr ab isnt conf and it is old hold
2947 )
2948 &&
2949 ( // old ab is curr hold
2950 ( oldAb.conferenceId && newHoldInfo.conferenceId && oldAb.conferenceId == newHoldInfo.conferenceId ) || // curr ab is conf and it is old hold
2951 ( ! oldAb.conferenceId && newHoldInfo.abonent && oldAb.key == newHoldInfo.abonent.key ) // or curr ab isnt conf and it is old hold
2952 )
2953 ) {
2954
2955 log('toggle was called');
2956
2957 } else*/ if ( that.currentSessionData.isAutoCall && ! data.abonent.isautocall && oldState == that.states.READY ) {
2958 that.state( that.states.BACKRING, oldAbonents );
2959 } else if ( data.abonent.isautocall ) {
2960 that.currentSessionData.isAutoCall = false;
2961 that.state( that.states.BACKCALL, oldAbonents );
2962 } else if ( data.abonent.isringing ) {
2963 if ( data.abonent.direction == 'acm_callback' || oldState == that.states.BACKRING ) {
2964 that.state( that.states.BACKRING, oldAbonents );
2965 } else {
2966 that.state( that.states.RING, oldAbonents );
2967 }
2968 } else if ( ( !( that.currentSessionData.isAutoCall ) && (
2969 data.abonent.iscommutated ||
2970 data.abonent.iswaitinginflash ||
2971 data.abonent.isconference ) ) ||
2972 ( data.linestatestr == 'lsCommutated' && data.abonent.isivr && ! data.abonent.isroutingivr )
2973 ) { // || data.abonent.isivr) ) {
2974 that.startTalkTimer(parseInt(data.timertalklensec) || 0);
2975 var newTalkStarted = that.currentSessionData.commStopped;
2976 that.currentSessionData.commStopped = false;
2977 that.state( that.states.TALK, oldAbonents, newTalkStarted );
2978 } else if ( data.abonent.extline || data.abonent.number ) { //
2979 that.currentSessionData.isAutoCall = false;
2980 that.state( that.states.CALL, oldAbonents );
2981 } else if ( data.linestatestr == 'lsDisconnected' ) {
2982 that.state( that.states.DISCONNECTED );
2983 } else if ( oldState == that.states.TALK && that.sipHasRTCSession ) {
2984
2985 } else if ( data.linestatestr != 'lsReserved' ) {
2986 that.currentSessionData = {};
2987 that.state( that.states.READY, oldAbonents );
2988// if ( oldState !== that.state() && that.sipActive ) {
2989// that.sip.hangup();
2990// }
2991 }
2992 }
2993
2994 if ( data.isflashing && data.flashed ) {
2995 that.setHold( data.flashed );
2996 } else {
2997 that.setHold(false);
2998 }
2999
3000 if ( data.abonent ) {
3001 if ( ! data.abonent.conferenceid ) {
3002 data.abonent.chainId = data.chainid;
3003 that.setAbonent( data.abonent, ( oldState == that.states.TALK && that.sipHasRTCSession ) || data.abonent.isivr || that.currentSessionData.isAutoCall );
3004 that.conferenceId(false);
3005 setStateFromResultData();
3006 callCallback();
3007 } else {
3008 that.conferenceId(data.abonent.conferenceid, true);
3009 that.loadConferenceInfo(function() {
3010 setStateFromResultData();
3011 callCallback();
3012 });
3013 }
3014 } else {
3015 callCallback();
3016 }
3017 } else {
3018 callCallback();
3019 }
3020
3021 });
3022 //});
3023 },
3024
3025 /**
3026 * Load current conference competitors
3027 * @param callback
3028 */
3029 loadConferenceInfo: function(callback) {
3030 var that = this;
3031 sendOktell('getconferenceinfo', { conferenceid: this.conferenceId() }, function(data) {
3032 that.setConfAbonentList(data.competitors);
3033 that.setConferenceInfo( data.conference );
3034 callFunc(callback,getReturnObj(data.result,data,1103,' getconferencecompetitors'));
3035 });
3036 },
3037
3038 /**
3039 * Create abonent object from loaded data
3040 * @param data
3041 * @return {*}
3042 */
3043 createAbonent: function(data) {
3044 var key = data.competitorid || data.number || data.userid || data.callerid || ( data.chainId != '00000000-0000-0000-0000-000000000000' && data.chainId );
3045 if ( ! key && data.isivr ) {
3046 key = newGuid();
3047 }
3048 if ( key ) {
3049 var abonent = new Abonent();
3050 extend(abonent, {
3051 key: key,
3052 guid: data.competitorid || data.userid,
3053
3054 isIvr: data.isivr,
3055 ivrName: data.ivrname || undefined,
3056
3057 isConferenceCompetitor: data.competitorid ? true : false,
3058 conferenceId : this.conferenceId(),
3059 isConferenceCreator: data.competitorid && data.iscreator ? true : undefined,
3060 isConferenceDirector: data.competitorid && data.isdirector ? true : undefined,
3061 isConferenceGhost: data.competitorid && data.isghost ? true : undefined,
3062 isConferenceGhostMajor: data.competitorid && data.isghostmajor ? true : undefined,
3063 isConferenceHidden: data.competitorid && data.ishidden ? true : undefined,
3064 isExternal: data.isextline ? true : false,
3065
3066 chainId: data.chainId,
3067
3068 phone: data.number ? data.number.toString() : ( data.calledid ? data.callerid.toString() : undefined ),
3069 phoneFormatted: data.number ? formatPhone( data.number.toString() ) : undefined,
3070
3071 name: data.simplename || data.username || data.name || data.caption || data.userlogin || data.number || data.ivrname,
3072
3073 isUser: data.userid ? true : false,
3074 user : {
3075 id: data.userid || undefined,
3076 name : data.username || undefined,
3077 login: data.userlogin || undefined,
3078 comment: data.comment || undefined
3079 },
3080
3081 isClient: undefined,
3082 client : {
3083 id: undefined,
3084 name: undefined
3085 },
3086 line: {
3087 id: undefined,
3088 number: undefined
3089 }
3090 });
3091 return abonent;
3092 }
3093 return false;
3094 },
3095
3096 /**
3097 * Set current abonent (for simple calls)
3098 * @param data - loaded info about abonent
3099 * @return {*}
3100 */
3101 setAbonent: function(data, saveOldAbonentIfEmpty) {
3102 var oldKey;
3103 if ( size(this.abonentList) ) {
3104 each(this.abonentList, function(ab,key) {
3105 oldKey = key;
3106 });
3107 }
3108 var oldAbonent = this.abonentList[oldKey];
3109 this.abonentList = {};
3110 var a = data ? this.createAbonent(data) : undefined;
3111 if ( a ) {
3112 this.abonentList[a.key] = a;
3113 if ( a.key != oldKey ) {
3114 self.trigger('abonentListChange', this.getAbonents() );
3115 self.trigger('abonentsChange', this.getAbonents(true) );
3116 }
3117 } else if ( oldAbonent && saveOldAbonentIfEmpty ) {
3118 this.abonentList[oldKey] = oldAbonent;
3119 } else if ( oldKey ) {
3120 self.trigger('abonentListChange', this.getAbonents() );
3121 self.trigger('abonentsChange', this.getAbonents(true) );
3122 }
3123 return this.abonentList;
3124 },
3125
3126 /**
3127 * Set abonents list from loaded conference's competitors list
3128 * @param abonents
3129 * @return {Boolean}
3130 */
3131 setConfAbonentList: function( abonents ) {
3132 var newList = {},
3133 that = this;
3134 if ( abonents && isArray(abonents) ) {
3135 each( abonents, function(ab) {
3136 if ( ! that.getConferenceInfo().isghost || ( that.getConferenceInfo().isghost && ( ab.isghost || ab.userid == oktellInfo.userid || ab.number == oktellInfo.number ) ) ) {
3137 newList[ ab.competitorid ] = true;
3138 if ( ! that.abonentList[ ab.competitorid ] ) {
3139 var a = that.createAbonent(ab);
3140 that.abonentList[a.key] = a;
3141 if ( that.conferenceId() && that.state() == that.states.TALK ) {
3142 self.trigger('conferenceAbonentEnter', that.abonentList[a.key] );
3143 }
3144 }
3145 }
3146 })
3147 }
3148 var localList = that.getAbonents();
3149 each( localList, function(ab,id) {
3150 if ( ! newList[id] ) {
3151 that.removeAbonents(id);
3152 }
3153 });
3154 self.trigger('abonentListChange', that.getAbonents() );
3155 self.trigger('abonentsChange', that.getAbonents(true) );
3156 return true;
3157 },
3158
3159 /**
3160 * Get current abonents list
3161 * @return {Object}
3162 */
3163 getAbonents: function( asArray ) {
3164 var list = asArray ? [] : {};
3165 each( this.abonentList, function(ab,i) {
3166 if ( asArray ) {
3167 list.push( cloneObject( ab ) );
3168 } else {
3169 list[i] = cloneObject( ab );
3170 }
3171 });
3172 return list;
3173 },
3174
3175 /**
3176 * Check, target is current abonent or not
3177 * @param number
3178 * @return {Boolean}
3179 */
3180 isAbonent: function( data, abonents ) {
3181 if ( ! data ) {
3182 return false;
3183 }
3184 abonents = abonents || this.getAbonents();
3185 if ( size(abonents) ) {
3186 if ( abonents.key ) {
3187 abonents = [abonents];
3188 }
3189 var curAb = false;
3190 each( abonents, function(ab) {
3191 if ( ( ab.guid && ab.guid == data ) ||
3192 ( ab.user && ab.user.id && ab.user.id == data ) ||
3193 ( ab.client && ab.client.id && ab.client.id == data ) ||
3194 ( ab.phone && ab.phone == data ) ) {
3195 curAb = cloneObject(ab);
3196 return breaker;
3197 }
3198 });
3199 return curAb;
3200 }
3201 return false;
3202 },
3203
3204 /**
3205 * Clear conference's abonents list
3206 */
3207 removeConfAbonents: function() {
3208 var that = this;
3209 each( that.abonentList, function(ab,i) {
3210 if ( that.conferenceId() && that.state() == that.states.TALK && ab.isConferenceCompetitor ) {
3211 self.trigger('conferenceAbonentLeave', ab);
3212 }
3213 delete that.abonentList[i];
3214 });
3215 },
3216
3217 /**
3218 * Remove abonent by number or id
3219 * @param number
3220 * @return {Boolean}
3221 */
3222 removeAbonents: function(number) {
3223 var that = this;
3224 if ( number && that.abonentList[number] ) {
3225 if ( that.conferenceId() && that.state() == that.states.TALK && that.abonentList[number].isConferenceCompetitor ) {
3226 self.trigger('conferenceAbonentLeave', that.abonentList[number]);
3227 }
3228 delete that.abonentList[number];
3229 self.trigger('abonentListChange', that.getAbonents() );
3230 self.trigger('abonentsChange', that.getAbonents(true) );
3231 } else if ( number === undefined && size(that.abonentList) ) {
3232 each( that.abonentList, function(ab,i) {
3233 if ( that.conferenceId() && that.state() == that.states.TALK && ab.isConferenceCompetitor ) {
3234 self.trigger('conferenceAbonentLeave', ab);
3235 }
3236 delete that.abonentList[i];
3237 });
3238 that.abonentList = {};
3239 } else {
3240 return false;
3241 }
3242 self.trigger('abonentListChange', that.getAbonents() );
3243 self.trigger('abonentsChange', that.getAbonents(true) );
3244 return true;
3245 },
3246
3247 /**
3248 * Back ring
3249 * @param number
3250 * @param callback
3251 * @return {Boolean}
3252 */
3253 makeCall: function(number, intercom, sequence, callback ) {
3254 var that = this;
3255 var error, msg = '';
3256 if ( ! number ) {
3257 error = 2106;
3258 }
3259 if ( userStates.state() == userStates.states.DISCONNECTED ) {
3260 error = 2001;
3261 }
3262 if ( that.state() == that.states.DISCONNECTED ) {
3263 error = 2002;
3264 }
3265 if ( that.getHoldInfo().hasHold && that.state() == that.states.TALK ) {
3266 error = 2101;
3267 }
3268 if ( that.conferenceId() ) {
3269 error = 2102;
3270 }
3271 if ( [ that.states.BACKCALL, that.states.BACKRING, that.states.CALL, that.states.RING ].indexOf(that.state()) != -1 ) {
3272 error = 2103;
3273 msg = ' (' + that.getStateStr() + ')';
3274 }
3275 if ( that.state() == that.states.READY && userStates.state() == userStates.states.BUSY && ! that.getHoldInfo().hasHold ) {
3276 error = 2104;
3277 }
3278
3279 if ( error ) {
3280 callFunc(callback, getErrorObj(error));
3281 return false;
3282 }
3283
3284 if ( that.isAbonent(number) ) {
3285 callFunc(callback, getErrorObj(2105));
3286 return false;
3287 } else if ( ( that.state() == that.states.READY ) && that.sipActive && ! intercom ) {
3288 if ( that.state() == that.states.TALK ) {
3289 that.sip.hold();
3290 }
3291 that.sip.call(number);
3292
3293 // find user or number and set it as abonent
3294 var user = users[number];
3295 var numberObj = numbers[number] || numbersById[number];
3296// if ( ! user && numberObj ) {
3297// each(users, function(u) {
3298// if ( u.numberObj == numberObj || u.number == number ) {
3299// user = u;
3300// return breaker;
3301// }
3302// });
3303// }
3304
3305// if ( user ) {
3306// log('setAbonent with user');
3307// that.setAbonent(user);
3308// } else if ( numberObj ) {
3309// log('setAbonent with numberObj');
3310// that.setAbonent(numberObj);
3311// } else {
3312// log('setAbonent with number');
3313// that.setAbonent({number:number});
3314// }
3315 callFunc(callback, getSuccessObj());
3316 } else if ( that.state() == that.states.READY || that.state() == that.states.TALK ) {
3317 // ######## #####
3318 // #### TALK - ####### ######## # ####, # ######## ##### ## number
3319 that.acmCall(number, intercom, sequence, function(data) {
3320 callFunc(callback, getReturnObj(data.result,data,2107));
3321 });
3322 } else {
3323 // #### ####### ## ###### (# ######)
3324 log('error call, unknown state');
3325 callFunc(callback, getErrorObj(2108));
3326 return false;
3327 }
3328 },
3329
3330 /**
3331 * Call server method for backcall
3332 * @param number
3333 * @param intercom - call in intercom mode
3334 * @param callback
3335 * @return {Boolean}
3336 */
3337 acmCall: function( number, intercom, sequence, callback ) {
3338 var that = this;
3339 sequence = ['abonent', 'user'].indexOf(sequence) !== -1 ? sequence : 'user';
3340 if ( ! number ) {
3341 return false;
3342 }
3343 var params = {
3344 sequence: intercom ? 'user' : sequence,
3345 intercom: intercom ? true : undefined
3346 };
3347 params.number = number.toString();
3348
3349 sendOktell( 'pbxautocallstart', params, function( data ) {
3350// that.loadStates(function() {
3351 callFunc(callback,data);
3352// });
3353 });
3354 },
3355
3356 /**
3357 * Switch current call and hold call
3358 * @param callback
3359 */
3360 toggleHold: function(callback) {
3361 var that = this;
3362 // TODO maybe it makes sense to load hold info from server before switch
3363 if ( that.getHoldInfo().hasHold ) {
3364 that.makeFlash('switch');
3365 callFunc(callback,getSuccessObj());
3366 } else {
3367 callFunc(callback,getErrorObj(2402));
3368 }
3369 },
3370
3371
3372 /**
3373 * Call flash method
3374 * @param mode ###
3375 * @param callback
3376 */
3377 makeFlash: function( mode ) {
3378 var that = this;
3379 var modeTypes = ['abort','switch','next'];
3380 sendOktell('pbxmakeflash',{ mode: modeTypes.indexOf(mode) != -1 ? mode : undefined });
3381 },
3382
3383 /**
3384 * Create conference or invite new competitor or make conference from current call
3385 * @param numbers or number for inviting to conference
3386 * @param callback
3387 */
3388 conference: function( numbers, callback ) {
3389 var that = this;
3390 numbers = toStringsArray(numbers);
3391
3392 if ( userStates.state() == userStates.states.BREAK ) {
3393 callFunc(callback,getErrorObj(2208));
3394 } else if ( that.state() == that.states.TALK ) {
3395 if ( that.conferenceId() && numbers ) {
3396 // invite
3397 that.inviteToConf(that.conferenceId(),numbers,callback);
3398 } else if ( ! that.conferenceId() ) {
3399 if ( ! numbers ) {
3400 that.callToConf(callback);
3401 } else {
3402 that.callToConf(function(data) {
3403 if ( data.result ) {
3404 that.inviteToConf(that.conferenceId(),numbers,callback);
3405 } else {
3406 callFunc(callback, getErrorObj(2202));
3407 }
3408 });
3409 }
3410 }
3411 } else if ( that.state() == that.states.READY && ! that.conferenceId() && numbers ) {
3412 // new conf
3413 that.createConf( numbers, callback);
3414 } else {
3415 callFunc(callback,getErrorObj(2205))
3416 }
3417 },
3418
3419 /**
3420 * Call server method for creating conference from current call
3421 * @param callback
3422 */
3423 callToConf: function(callback) {
3424 var that = this;
3425 that.buildConfFromCommCallback = callback;
3426 that.buildConfFromCommTimer = setTimeout(function() {
3427 callFunc(that.buildConfFromCommCallback, getErrorObj(2202));
3428 that.buildConfFromCommCallback = undefined;
3429 },2000)
3430 sendOktell('buildconferencefromcommutation');
3431 },
3432
3433 /**
3434 * Call server method for creating conference
3435 * @param numbers
3436 * @param callback
3437 */
3438 createConf: function( numbers, callback ) {
3439 var that = this;
3440 var confId = newGuid();
3441 var room = Math.round( Math.random() * 10000 );
3442 var numParam = [{ userlogin: oktellInfo.login }];
3443 numbers = toStringsArray(numbers);
3444 if ( isArray( numbers ) ) {
3445 each( numbers, function(n) {
3446 if ( isGuid(n) ) {
3447 numParam.push({ userid: n });
3448 } else {
3449 if ( oktellInfo.oktellDated >= that._oktellDatedWithConfNumber ) {
3450 numParam.push({ number: n });
3451 } else {
3452 numParam.push({ intnumber: n });
3453 }
3454 }
3455 });
3456 }
3457
3458 if ( size(numParam) > 1 ) {
3459 sendOktell('createnewconference', {
3460 conference: {
3461 id: confId,
3462 room: room,
3463 name: "",
3464 description: "",
3465 accessmode: "free",
3466 isselector: false,
3467 record: true,
3468 recordrights: "selected",
3469 everyonecaninvite: true,
3470 canvieweachother: true
3471 },
3472 competitors: numParam
3473 } , function(data) {
3474 if ( data.result == 1 ) {
3475 that.conferenceId(confId, true);
3476 } else {
3477 that.conferenceId(false);
3478 }
3479 callFunc(callback,getReturnObj(data.result, data, 2204));
3480 });
3481 } else {
3482 callFunc(callback, getErrorObj(2203));
3483 }
3484 },
3485
3486 /**
3487 * Call server method for inviting competitors to conference
3488 * @param confId conference id
3489 * @param numbers or number for invite
3490 * @param callback
3491 */
3492 inviteToConf: function( confId, numbers, callback ) {
3493 if ( ! confId ) {
3494 callFunc(callback,false);
3495 }
3496 var that = this;
3497 numbers = toStringsArray(numbers);
3498 var numParam = [];
3499 var fromHold;
3500 var holdAbonent = that.getHoldInfo().abonent || {};
3501 if ( isArray( numbers ) ) {
3502 each( numbers, function(n) {
3503 if ( typeof n == 'string' && n !== '' ) {
3504 if ( that.isAbonent(n, holdAbonent) ) {
3505 fromHold = n;
3506 } else {
3507 if ( isGuid(n) ) {
3508 numParam.push({ userid: n });
3509 } else {
3510 numParam.push({ number: n });
3511 }
3512 }
3513 }
3514 });
3515 }
3516
3517 var sendInvites = function() {
3518 sendOktell('invitetoconference', { conferenceid: confId, competitors: numParam}, function(data) {
3519 callFunc(callback, getReturnObj(data.result,data,2202));
3520 });
3521 }
3522
3523 if ( size(numParam) == 0 && ! fromHold ) {
3524 callFunc(callback,getErrorObj(2201));
3525 } else if ( fromHold ) {
3526 if ( confId != that.conferenceId() ) {
3527 callFunc(callback, getErrorObj(2206));
3528 return;
3529 }
3530 sendOktell('checkcanconnecttogathertoconference', {}, function(data) {
3531 if ( data.canconnecttogather ) {
3532 sendOktell('connecttogathertoconference');
3533 if ( size(numParam) != 0 ) {
3534 sendInvites();
3535 } else {
3536 callFunc(callback, getSuccessObj());
3537 }
3538 } else {
3539 callFunc(callback, getErrorObj(2206));
3540 }
3541 });
3542 } else if ( size(numParam) != 0 ) {
3543 sendInvites();
3544 } else {
3545 callFunc(callback, getErrorObj(2207));
3546 }
3547 },
3548
3549 /**
3550 * Stop call, dial, conference. Disconnection of conference competitor
3551 * @param numbers or number for disconnect
3552 */
3553 endCall: function( numbers ) {
3554 var that = this;
3555 numbers = toStringsArray(numbers);
3556 var isAbonent = false;
3557 var isMe = false;
3558 if ( numbers ) {
3559 each(numbers, function(n) {
3560 if ( ! isAbonent && that.isAbonent(n) ) {
3561 isAbonent = true;
3562 }
3563 if ( ! isMe && ( n == oktellInfo.number || n == oktellInfo.userid ) ) {
3564 isMe = true;
3565 }
3566 });
3567 }
3568
3569 if ( ! numbers ) {
3570 if ( that.state() == that.states.TALK || that.state() == that.states.CALL || that.getHoldInfo().hasHold ) {
3571 that.abortCall();
3572 } else if ( that.state() == that.states.BACKCALL ) {
3573 that.abortAcmCall();
3574 } else if ( that.state() == that.states.RING || that.state() == that.states.BACKRING ) {
3575 that.declineCall();
3576 }
3577 } else if ( that.getHoldInfo().hasHold && ( isMe || ( ! that.conferenceId() && isAbonent ) ) ) {
3578 that.makeFlash('abort');
3579 } else if ( isAbonent || isMe ) {
3580 if ( that.state() == that.states.TALK ) {
3581 if ( that.conferenceId() ) {
3582 that.kickConfAbonent( that.conferenceId(), numbers);
3583 } else {
3584 that.abortCall();
3585 }
3586 } else if ( that.state() == that.states.BACKCALL ) {
3587 that.abortAcmCall();
3588 } else if ( that.state() == that.states.CALL ) {
3589 that.abortCall();
3590 } else if ( that.state() == that.states.RING || that.state() == that.states.BACKRING ) {
3591 that.declineCall();
3592 }
3593 }
3594 },
3595
3596 /**
3597 * Call server method for disconnect current connection
3598 */
3599 abortCall: function() {
3600 sendOktell('pbxabortcall');
3601 },
3602
3603 /**
3604 * Call server method for end commutation if exist, stop autocall if started
3605 */
3606 declineCall: function() {
3607 sendOktell('pbxdeclinecall');
3608 },
3609
3610 /**
3611 * Call server method for disconnect conference competitor by number
3612 * @param confId conference id
3613 * @param numbers or number
3614 */
3615 kickConfAbonent: function( confId, numbers ) {
3616 numbers = toStringsArray(numbers);
3617 var that = this;
3618 sendOktell('getconferencecompetitors', { conferenceid: confId }, function(data) {
3619 var compsByNumber = {};
3620 var compsById = {};
3621 var iam = false;
3622 for ( var i = 0, l = data.competitorlist.length; i < l; i++ ) {
3623// if ( data.competitorlist[i].number != oktellInfo.number ) {
3624// compsByNumber[data.competitorlist[i].number] = data.competitorlist[i].competitorid;
3625// } else {
3626// iam = true;
3627// }
3628// if ( data.competitorlist[i].userid != oktellInfo.userid ) {
3629// compsById[data.competitorlist[i].userid] = data.competitorlist[i].competitorid;
3630// } else {
3631// iam = true;
3632// }
3633 compsByNumber[data.competitorlist[i].number] = data.competitorlist[i].competitorid;
3634 compsById[data.competitorlist[i].userid] = data.competitorlist[i].competitorid;
3635 }
3636 var n;
3637 each( numbers, function(num) {
3638 if ( n = ( compsByNumber[num] || compsById[num] || '' ) ) {
3639 if ( num && ( num == oktellInfo.number || num == oktellInfo.userid ) ) {
3640 iam = true;
3641 } else {
3642 sendOktell('confdisconnectcompetitor', {conferenceid: confId, competitor: { competitorid: n } } );
3643 }
3644 }
3645 });
3646 if ( iam ) {
3647 that.exitConf(confId);
3648 }
3649 });
3650 },
3651
3652 /**
3653 * Call server method for stop back ring
3654 * @param callback
3655 */
3656 abortAcmCall: function(callback) {
3657 sendOktell('pbxautocallabort');
3658 },
3659
3660 /**
3661 * Call method for exit conference
3662 * @param confId
3663 */
3664 exitConf : function( confId ) {
3665 sendOktell('exitconference', {conferenceid:confId});
3666 },
3667
3668 /**
3669 * Call method for transfer call
3670 * @param transferTo
3671 * @param callback
3672 */
3673 makeTransfer: function( transferTo, callback ) {
3674 sendOktell('pbxmaketransfer',{
3675 transferto: transferTo ? transferTo + '' : ""
3676 });
3677 callFunc(callback, getSuccessObj());
3678 },
3679
3680 /**
3681 * Transfer call
3682 * @param number
3683 * @param callback
3684 */
3685 transfer: function( number, callback ) {
3686 var that = this;
3687 if ( ! number ) {
3688 callFunc(callback, getErrorObj(2304));
3689 }
3690
3691 if ( that.state() == that.states.TALK ) {
3692 if ( that.getHoldInfo().hasHold ) {
3693 if ( ! number || that.isAbonent( number, that.getHoldInfo().abonent || {} ) ) {
3694 // connect B to A, we disconnect
3695 that.endCall(undefined);
3696 callFunc(callback,getSuccessObj());
3697 } else {
3698 // connect B to C, we connect to A
3699 that.makeTransfer(number, callback);
3700 }
3701 } else if ( number ) {
3702 // connect A to B, we disconnect
3703 that.makeTransfer( number, callback);
3704 } else {
3705 callFunc(callback, getErrorObj(2302));
3706 }
3707 } else {
3708 callFunc(callback, getErrorObj(2303));
3709 }
3710 },
3711
3712 /**
3713 * Connect for help or wiretapping, change connection type
3714 * @param target
3715 * @param mode
3716 * @param callback
3717 * @return {Boolean}
3718 */
3719 ghost: function( target, mode, callback ) {
3720 var that = this;
3721
3722 var fn = function(d) {
3723 that.loadConferenceInfo( callFunc(callback,d) );
3724 };
3725
3726 target = ( users[target] && users[target].id ) || (numbers[target] && numbers[target].userid);
3727 if ( ! target ) {
3728 callFunc(fn, getErrorObj(2504));
3729 return false;
3730 }
3731
3732 mode = mode || 'monitor';
3733
3734 if ( ['monitor', 'conference', 'help'].indexOf(mode) == -1 ) {
3735 callFunc( fn, getErrorObj(2503));
3736 return false;
3737 }
3738
3739
3740 if ( that.state() == that.states.READY ) {
3741
3742 sendOktell('attachasghost', { ghostedid: target }, function(data) {
3743 if ( data.result ) {
3744 if ( mode && mode != 'monitor' ) {
3745 setTimeout(function() {
3746 if ( that.conferenceId() ) {
3747 that.changeGhostMode( mode, fn );
3748 }
3749 }, 500);
3750 } else {
3751 callFunc(fn, getSuccessObj());
3752 }
3753 } else {
3754 if ( data.error == 52710 ) {
3755 callFunc(fn, getErrorObj(2505));
3756 } else {
3757 callFunc(fn, getErrorObj(2502));
3758 }
3759 }
3760 });
3761
3762 } else {
3763
3764 var ab = that.isAbonent(oktellInfo.userid);
3765 var conferenceId = that.conferenceId();
3766 if ( ! ab || ! conferenceId || ! that.getConferenceInfo().isghost ) {
3767 callFunc( fn, getErrorObj(2506));
3768 return false;
3769 }
3770
3771 var targetAbonent = that.isAbonent( target );
3772 if ( ! targetAbonent ) {
3773 callFunc( fn, getErrorObj(2507));
3774 return false;
3775 }
3776
3777 if ( ! targetAbonent.isConferenceGhostMajor && ( mode == 'help' || mode == 'monitor' ) ) {
3778
3779 sendOktell('confsetvoiceparams', {
3780 conferenceid: conferenceId,
3781 competitor: {
3782 competitorid: targetAbonent.guid,
3783 ghosthelp: mode == 'help' ? true : false
3784 }
3785 }, function(data) {
3786 if ( data.result ) {
3787
3788 }
3789 callFunc(fn,getReturnObj(data.result,{},2502));
3790 });
3791
3792 } else {
3793
3794 sendOktell('confsetghostmode', { conferenceid: conferenceId, ghostmode: mode }, function(data) {
3795 if ( data.result ) {
3796
3797 }
3798 callFunc(fn,getReturnObj(data.result,{},2502));
3799 });
3800
3801 }
3802 }
3803 },
3804
3805 /**
3806 * Load waiting queue
3807 * @param callback
3808 */
3809 queue: function(callback) {
3810 var that = this;
3811 sendOktell('getcurrentqueue', {}, function(data) {
3812 if ( data.result ) {
3813 var abonents = {},
3814 absArr = [],
3815 listChanged = false;
3816 if ( isArray( data.queue ) && size(data.queue) > 0 ) {
3817 each( data.queue, function(q) {
3818 ab = that.createAbonent(q)
3819 abonents[ab.key] = ab;
3820 absArr.push(ab);
3821 if ( ! that.queueList[ab.key] && ! that.isAbonent(ab.key) ) {
3822 that.queueList[ab.key] = ab;
3823 self.trigger('queueAbonentEnter', ab)
3824 listChanged = true;
3825 }
3826 });
3827 }
3828 each( that.queueList, function(ab, key) {
3829 if ( ! abonents[key] ) {
3830 self.trigger('queueAbonentLeave', ab)
3831 delete that.queueList[key];
3832 listChanged = true;
3833 }
3834 });
3835 if ( listChanged ) {
3836 self.trigger('queueChange', absArr);
3837 }
3838 callFunc(callback, getSuccessObj({queue: absArr}));
3839 } else {
3840 callFunc(callback, getErrorObj(2701));
3841 }
3842 });
3843 },
3844
3845
3846
3847 startTalkTimer: function(seconds) {
3848 var that = this;
3849 that.clearTalkTimer(true);
3850 that._talkLength = Date.now() - ( parseInt(seconds) || 0 ) * 1000;
3851 that.triggerTalkTimeEvent()
3852 that._talkTimer = setInterval(function() {
3853 that.triggerTalkTimeEvent()
3854 },1000);
3855 },
3856
3857 triggerTalkTimeEvent: function() {
3858 var that = this;
3859 if ( that._talkLength !== false ) {
3860 var len = that.getCurrentTalkLength()
3861 self.trigger('talkTimer', len, that.formatTime(len) );
3862 } else {
3863 self.trigger('talkTimer', false );
3864 }
3865 },
3866
3867 getCurrentTalkLength: function() {
3868 return Math.floor( (Date.now() - this._talkLength) / 1000 )
3869 },
3870
3871 clearTalkTimer: function(silent) {
3872 clearInterval( this._talkTimer );
3873 this._talkLength = false
3874 if ( ! silent ) {
3875 this.triggerTalkTimeEvent()
3876 }
3877 },
3878
3879 formatTime: function(sec) {
3880 var t = sec,
3881 h = Math.floor(t/3600),
3882 m = Math.floor(t/60) % 60,
3883 s = t%60;
3884 return ( h ? h + ':' : '' ) +
3885 ( m < 10 ? '0' + m : m ) + ':' +
3886 ( s < 10 ? '0' + s : s );
3887 },
3888
3889 talkLength: function(format) {
3890 if ( this._talkLength === false ) {
3891 return '';
3892 }
3893 var sec = this.getCurrentTalkLength()
3894 if ( format ) {
3895 return this.formatTime(sec);
3896 } else {
3897 return sec;
3898 }
3899 },
3900
3901 dtmf: function(code) {
3902 if ( ! this.sipActive || typeof code != 'string' || !code.match(/^[0-9\*#]{1}$/) ) {
3903 return false;
3904 }
3905 return this.sip.dtmf(code);
3906 },
3907
3908 hold: function() {
3909 if ( this.sipActive ) {
3910 this.sip.hold();
3911 } else if ( this.state() == this.states.TALK || this.getHoldInfo().hasHold ) {
3912 this.makeFlash('switch');
3913 }
3914 },
3915
3916 resume: function() {
3917 if ( this.getHoldInfo().hasHold && this.sipActive ) { this.sip.resume(); }
3918 }
3919 };
3920 extend( phone, Events );
3921 exportApi('isAbonent', phone.isAbonent, phone);
3922 exportApi('conferenceId', phone.conferenceId, phone);
3923 exportApi('getHoldInfo', phone.getHoldInfo, phone);
3924 exportApi('endCall', phone.endCall, phone);
3925 exportApi('conference', phone.conference, phone);
3926 exportApi('transfer', phone.transfer, phone);
3927 exportApi('toggle', phone.toggleHold, phone);
3928 exportApi('getState', phone.apiGetStateStr, phone);
3929 exportApi('getQueue', phone.queue, phone);
3930 exportApi('getTalkLength', phone.talkLength, phone);
3931 exportApi('answer', phone.answer, phone);
3932 exportApi('dtmf', phone.dtmf, phone);
3933 exportApi('hold', phone.hold, phone);
3934 exportApi('resume', phone.resume, phone);
3935// exportApi('getPhoneState', phone.apiGetPhoneState, phone);
3936
3937
3938 /**
3939 * Possible actions for phone states
3940 * @type {Object}
3941 */
3942 var pa = {};
3943 pa['-'] = {}
3944 pa[phone.states.DISCONNECTED] = {};
3945 pa[phone.states.BACKCALL] = { endCall: 1 };
3946 pa[phone.states.BACKRING] = { endCall: 1, answer: 1 };
3947 pa[phone.states.CALL] = { endCall: 1, conference: 1, call: 1, intercom: 1, transfer: 1 };
3948 pa[phone.states.READY] = { conference: 1, call: 1, intercom: 1, ghostListen: 1, ghostHelp: 1, ghostConference: 1, transfer: 1, toggle: 1, endCall: 1, resume: 1 };
3949 pa[phone.states.RING] = { endCall: 1, answer: 1 };
3950 pa[phone.states.TALK] = { endCall: 1, conference: 1, call: 1, resume: 1, hold: 1, intercom: 1, toggle: 1, transfer: 1, ghostListen: 1, ghostHelp: 1, ghostConference: 1 };
3951 //pa[phone.states.CALLWEBPHONE] = { };
3952
3953 /**
3954 * Possible actions for user states
3955 * @type {Object}
3956 */
3957 var pau = {};
3958 pau['-'] = {}
3959 pau[userStates.states.DISCONNECTED] = {};
3960 pau[userStates.states.READY] = {endCall: 1, conference: 1, call: 1, intercom: 1, toggle: 1, transfer: 1, resume: 1, ghostListen: 1, ghostHelp: 1, ghostConference: 1, resume:1};
3961 pau[userStates.states.BREAK] = {endCall: 1, call: 1, intercom: 1, toggle: 1, transfer: 1, ghostListen: 1, resume: 1, ghostHelp: 1, ghostConference: 1};
3962 pau[userStates.states.OFF] = {endCall: 1, conference: 1, call: 1, intercom: 1, toggle: 1, transfer: 1, resume: 1, ghostListen: 1, ghostHelp: 1, ghostConference: 1};
3963 pau[userStates.states.BUSY] = {answer: 1, endCall: 1, conference: 1, call: 1, intercom: 1, toggle: 1, transfer: 1, resume: 1, hold: 1, ghostListen: 1, ghostHelp: 1, ghostConference: 1};
3964 pau[userStates.states.RESERVED] = {};
3965 pau[userStates.states.NOPHONE] = {};
3966
3967
3968
3969 /**
3970 * Phone actions class
3971 * @constructor
3972 */
3973 var PhoneActions = function() {
3974 var a = [];
3975 var s = phone.state();
3976 s = typeof s == 'number' ? s : '-';
3977 var us = userStates.state() || '-';
3978 us = typeof us == 'number' ? us : '-';
3979 this.push = function() {
3980 each( arguments, function(arg) {
3981 if ( pa[s][arg] && pau[us][arg] ) {
3982 a.push(arg);
3983 }
3984 })
3985 };
3986 this.getActions = function() {
3987 return a;
3988 }
3989 }
3990
3991 /**
3992 * Return possible actions by phone number or userid
3993 * @param data
3994 * @return {*}
3995 */
3996 var getPhoneActions = function( data ) {
3997 var a = new PhoneActions;
3998 if ( ! data || ! serverConnected() ) {
3999 return a.getActions();
4000 }
4001 // if user has number, but number doesn't exist in numbers, use users's number as argument
4002 if ( users[data] && users[data].number && ! numbers[data] && ! numbersById[data] ) {
4003 data = users[data].number;
4004 }
4005 var isMe = oktellInfo.userid == data || oktellInfo.number == data;
4006 var hold = phone.isAbonent(data, phone.getHoldInfo().abonent || {} );
4007 var obj = users[data] || numbers[data] || numbersById[data];
4008 if ( obj && obj.numberObj ) {
4009 obj = obj.numberObj;
4010 }
4011 var abonent = phone.isAbonent(data) || ( obj && obj.number && phone.isAbonent(obj.number) );
4012 var isInQueue = phone.isAbonent(data, phone.queueList) || ( obj && obj.number && phone.isAbonent(obj.number, phone.queueList) );
4013 var hasHold = phone.getHoldInfo().hasHold;
4014 var isConf = phone.conferenceId() ? true : false;
4015 var isConfCreator = isConf && abonent && abonent.isConferenceCreator;
4016 var iAmAbonent = isConf && phone.isAbonent( oktellInfo.userid );
4017 var iAmCreator = isConf && iAmAbonent && iAmAbonent.isConferenceCreator;
4018 var phoneState = phone.state();
4019 var intercomSupport = phone.intercomSupport;
4020
4021 if ( isInQueue ) {
4022
4023 } else if ( isMe ) {
4024 if ( phoneState != phone.states.DISCONNECTED && phoneState != phone.states.READY ) {
4025 if ( ( phoneState == phone.states.RING || phoneState == phone.states.BACKRING ) && ( phone.sipActive || intercomSupport !== false ) ) {
4026 a.push('answer');
4027 }
4028 a.push('endCall');
4029 }
4030 } else if ( ! obj || ( obj && obj.state !== undefined && obj.state != 0 ) ) {
4031 if ( hold ) {
4032 if ( phone.sipActive && phone.sip && typeof phone.sip.isOnHold === "function" && phone.sip.isOnHold() ) {
4033 a.push('resume');
4034 } else {
4035 a.push('toggle', 'endCall'); // toogle and connect current with hold, and disconnect myself
4036 }
4037 } else if ( ! abonent ) {
4038 if ( isConf ) {
4039 if ( ! ( obj && obj.state == 2 ) ) {
4040 a.push('conference');
4041 }
4042 a.push('transfer');
4043 } else {
4044 if ( ( ! hasHold && phoneState == phone.states.TALK ) || phoneState == phone.states.READY ) {
4045 a.push('call');
4046 if ( phoneState == phone.states.TALK ) {
4047 a.push('transfer');
4048 }
4049 if ( ! ( obj && obj.state == 2 ) ) {
4050 a.push('conference');
4051 }
4052 a.push('intercom');
4053 } else if ( hasHold && phoneState == phone.states.TALK ) {
4054 a.push('transfer');
4055 }
4056 }
4057 //log(phone.state() + userControlledByMe(data));
4058 if ( obj && obj.state == 5 && phoneState == phone.states.READY && userControlledByMe(data) ) {
4059 a.push('ghostListen', 'ghostHelp', 'ghostConference');
4060 }
4061 } else if ( abonent ) {
4062 if ( ( phoneState == phone.states.RING || phoneState == phone.states.BACKRING ) && ( phone.sipActive || intercomSupport !== false ) ) {
4063 a.push('answer');
4064 }
4065 if ( isConf ) {
4066 if ( iAmCreator ) {
4067 a.push('endCall');
4068 }
4069 } else {
4070 a.push('endCall');
4071 if ( phone.sipActive && ! hasHold ) {
4072 a.push('hold');
4073 }
4074 if ( ! ( obj && obj.state == 2 ) ) {
4075 a.push('conference');
4076 }
4077// if ( hasHold ) {
4078// a.push('transfer');
4079// }
4080 }
4081 if ( phone.getConferenceInfo().isghost && userControlledByMe(data) ) {
4082 a.push('ghostListen', 'ghostHelp', 'ghostConference');
4083 }
4084 }
4085 }
4086 //log('Phone action for ' + data + ' ' + a.getActions());
4087 return a.getActions();
4088 };
4089 exportApi('getPhoneActions',getPhoneActions);
4090
4091 startQueueTimer = function(timeout) {
4092 clearInterval(queueTimer);
4093 queueTimer = setInterval(function() {
4094 if ( serverConnected() ) {
4095 phone.queue()
4096 }
4097 }, timeout);
4098 }
4099
4100 /**
4101 * connect with server
4102 * @param options
4103 * @param callback
4104 * @return {Boolean}
4105 */
4106 var connect = function( options, callback ) {
4107
4108 self.trigger('connecting');
4109
4110 if ( serverConnected() ) {
4111 return true;
4112 }
4113
4114 options = options || {};
4115 var loginError = false;
4116
4117 extend( oktellOptions, options );
4118 debugMode = oktellOptions.debugMode;
4119 oktellVoice = false
4120 if ( oktellOptions.oktellVoice ) {
4121 if ( oktellOptions.oktellVoice.isOktellVoice === true ) {
4122 oktellVoice = oktellOptions.oktellVoice
4123 } else if ( window.oktellVoice && window.oktellVoice.isOktellVoice === true ) {
4124 oktellVoice = window.oktellVoice
4125 }
4126 }
4127
4128 var sessionId = cookie(cookieSessionName) || ( localStorage && localStorage[cookieSessionName] );
4129
4130 if ( ! sessionId && options.password !== undefined && options.password !== null ) {
4131 oktellOptions.password = md5( utf8DecodePass( options.password.toString().toLowerCase() ) );
4132 oktellOptions.Password = md5( utf8DecodePass( options.password.toString() ) );
4133 } else {
4134 oktellOptions.password = undefined;
4135 oktellOptions.Password = undefined;
4136 }
4137
4138
4139 var wsProtocolUrlRegExp = /^w[s]{1,2}:\/\/\S+$/,
4140 portRegExp = /:[0-9]{1,5}$/;
4141 var prepareUrl = function(urlStr) {
4142 if ( wsProtocolUrlRegExp.test(urlStr) ){
4143 return urlStr;
4144 } else {
4145 var useWss = location.protocol == 'https:',
4146 port = useWss ? ':443' : ':80',
4147 protocol = useWss ? 'wss://' : 'ws://';
4148 if ( portRegExp.test(urlStr) ) {
4149 return protocol + urlStr;
4150 } else {
4151 return protocol + urlStr + port;
4152 }
4153 }
4154 return false;
4155 }
4156
4157 if ( typeof oktellOptions.url == 'string' ) {
4158 oktellOptions.url = [oktellOptions.url];
4159 }
4160
4161 if ( isArray(oktellOptions.url) ) {
4162 var links = []
4163 for ( var i = 0, j = oktellOptions.url.length; i < j; i++ ) {
4164 if ( typeof oktellOptions.url[i] !== 'string') {
4165 continue;
4166 }
4167 links.push( prepareUrl(oktellOptions.url[i]) );
4168 }
4169 oktellOptions.url = links;
4170 } else {
4171 callFunc( oktellOptions.callback, getErrorObj(1205) );
4172 self.trigger('connectError', getErrorObj(1205) );
4173 return false;
4174 }
4175
4176 oktellInfo.url = oktellOptions.url;
4177 oktellInfo.login = oktellOptions.login;
4178 oktellInfo.defaultAvatar = oktellOptions.defaultAvatar;
4179 oktellInfo.defaultAvatar32x32 = oktellOptions.defaultAvatar32x32;
4180 oktellInfo.defaultAvatar64x64 = oktellOptions.defaultAvatar64x64;
4181
4182 var currentUrlIndex = 0;
4183
4184 if ( ! sessionId && ( oktellOptions.password === undefined || oktellOptions.password === null ) ) {
4185 callFunc( oktellOptions.callback, getErrorObj(1213) );
4186 self.trigger('connectError', getErrorObj(1213) );
4187 return false;
4188 }
4189
4190 var createServer = function() {
4191 server = new Server( oktellOptions.url, oktellOptions.openTimeout, oktellOptions.queryDelayMin, oktellOptions.queryDelayMax, function(url) {
4192 //alert(url);
4193 loginError = false;
4194 oktellInfo.currentUrl = server.url; //oktellOptions.url[currentUrlIndex];
4195 sendOktell('login', {
4196 Password: oktellOptions.Password,
4197 password: oktellOptions.password,
4198 sessionid: sessionId || undefined,
4199 showid: 1,
4200 usewebrtc: oktellVoice ? true : false,
4201 workplace: oktellOptions.workplace || undefined,
4202 expires: oktellOptions.expires || undefined
4203 }, function(data) {
4204 loginError = true;
4205 var getLoginErrorObj = function(code) {
4206 return getErrorObj(errorCode, '', {
4207 serverErrorMessage: data.errormsg,
4208 serverErrorCode: data.error
4209 });
4210 }
4211 if ( data.error || data.errormsg ) {
4212 var errorCode = 1000;
4213 if ( data.error == 50093 ) {
4214 errorCode = 1204; // ############ ### ###############
4215 } else if ( data.error == 50025 ) {
4216 errorCode = 1214; // ########## #############, ############ ########## # ########, ########## #########
4217 } else if ( data.errormsg == "Service not available" ) {
4218 errorCode = 1215; // ###### ###### #############
4219 } else if( data.errormsg == "Wrong login/pass combination" ) {
4220 cookie(cookieSessionName, null);
4221 localStorage && (delete localStorage[cookieSessionName]);
4222 errorCode = 1202;
4223 } else if ( data.errormsg == 'Bad request. Session does not exist' || data.errormsg == 'Bad request. Invalid session user' ) {
4224 cookie(cookieSessionName, null);
4225 localStorage && (delete localStorage[cookieSessionName]);
4226 errorCode = 1212;
4227 }
4228 callFunc( oktellOptions.callback, getLoginErrorObj(errorCode) );
4229 self.trigger('connectError', getLoginErrorObj(errorCode) );
4230 disconnect(14);
4231 } else if (data.result == 1) {
4232 clearInterval(pingTimer);
4233 pingTimer = setInterval(function() {
4234 if ( serverConnected() ) {
4235 server.sendOktell('ping');
4236 }
4237 },15000);
4238 startQueueTimer(oktellOptions.queueInterval);
4239 phone.queue();
4240 customEvents.sendCustomBinding();
4241
4242 server.bindOktellEvent('userstatechanged', function(data) {
4243 userStates.saveStatesFromServer(data);
4244 });
4245
4246 if ( oktellVoice ) {
4247 setTimeout(function() {
4248 sipPhone = oktellVoice.connect({
4249 login: data.sipuser,
4250 password: data.sippass,
4251 server: url.replace(/w[s]{1,2}:\/\//, '').replace('/', '').split(':')[0] + ':' + data.sipport,
4252 useWSS: data.sipsecure,
4253 debugMode: debugMode
4254 });
4255 if ( sipPhone ) {
4256 sipPhone.on('connect', function() {
4257 sipPnoneActive = true;
4258 self.trigger('webphoneConnect');
4259 });
4260 sipPhone.on('all', function(event) {
4261 log('Oktell webphone event: ' + event, arguments);
4262 });
4263 sipPhone.on('disconnect', function() {
4264 sipPnoneActive = true;
4265 self.trigger('webphoneDisconnect');
4266 });
4267 phone.setSipPhone(sipPhone);
4268 }
4269 }, 200);
4270 }
4271
4272 oktellInfo.userid = data.userid;
4273 oktellInfo.sessionId = data.sessionid;
4274 if (oktellInfo.sessionId) {
4275 cookie(cookieSessionName, oktellInfo.sessionId, { expires: oktellOptions.expires });
4276 localStorage && (localStorage[cookieSessionName] = oktellInfo.sessionId);
4277 }
4278
4279 sendOktell('getversion', {showalloweddbstoredprocs:1}, function(data) {
4280
4281 if ( data.result ) {
4282 oktellInfo.oktellDated = data.version.dated;
4283 oktellInfo.oktellBuild = data.version.build;
4284
4285 // ######### ########## #####-###### ######, ### ###### ###### 2.11.1.140905 ######## 2.11.xxxx.xxxxx
4286 if ( oktellInfo.oktellDated < 140918 && /2\.11\.[0-9]{4}\.[0-9]{5}/g.test(oktellInfo.oktellBuild) ){
4287 oktellInfo.oktellBuild = "2.11.1." + oktellInfo.oktellDated
4288 }
4289
4290 oktellInfo.allowedProcedures = data.alloweddbstoredprocs || {};
4291 oktellInfo.oktellWebServerPort = data.version.webserverport;
4292 oktellInfo.oktellWebServerLink = getWebServerLink();
4293 if ( ! isValidMethodVersion('pbxanswercall') ) {
4294 phone.intercomSupport = false;
4295 }
4296
4297 sendOktell('getmyuserinfo', {}, function(data) {
4298 if ( data.result ) {
4299 oktellInfo.number = data.mainpbxnumber;
4300 oktellInfo.username = data.username;
4301 oktellInfo.hasline = data.hasline;
4302 oktellInfo.lineid = data.lineid;
4303 oktellInfo.linenumber = data.linenumber;
4304 oktellInfo.isoperator = data.isoperator;
4305 userStates.loadBreakReasons(function(data) {
4306 userStates.loadState(function(result) {
4307 if ( result ) {
4308 userStates.checkUserRedirect(function(result) {
4309 loadPbxNumbers(function() {
4310
4311 server.bindOktellEvent( 'pbxnumberstatechanged', function( data ) {
4312 for( var i = 0; i < data.numbers.length; i++ ) {
4313 var n = numbers[ data.numbers[i].num ];
4314 if ( n ) {
4315 n.state = data.numbers[i].numstateid;
4316 }
4317 }
4318 });
4319
4320 loadUsers(function() {
4321 phone.loadStates(function(result) {
4322 if ( result ) {
4323 loginError = false;
4324 events.trigger('login');
4325 server.bindOktellEvent('httpresponsecopy',function(data) {
4326 var result = data.response;
4327 if ( result == '200 OK') {
4328 var pass = data.password;
4329 var content = data.content;
4330 if ( httpQueryData[pass] && typeof httpQueryData[pass].callback == 'function' ) {
4331 httpQueryData[pass].callback(content);
4332 }
4333 }
4334 });
4335 callFunc( oktellOptions.callback, getSuccessObj() );
4336 oktellConnected(true);
4337
4338 for (var i = 0; i < nativeEventsForBindAfterConnect.length; i++) {
4339 var obj = nativeEventsForBindAfterConnect[i];
4340 if ( obj && obj.eventName && obj.callback && ! obj.binded ) {
4341 obj.binded = true;
4342 server.bindOktellEvent(obj.eventName, obj.callback);
4343 }
4344 }
4345
4346 self.trigger('connect');
4347 } else {
4348 callFunc( oktellOptions.callback, getLoginErrorObj(1207) );
4349 self.trigger('connectError', getLoginErrorObj(1207) );
4350 disconnect(14);
4351 }
4352 });
4353 });
4354 });
4355 });
4356 } else {
4357 callFunc( oktellOptions.callback, getLoginErrorObj(1209) );
4358 self.trigger('connectError', getLoginErrorObj(1209) );
4359 disconnect(14);
4360 }
4361 });
4362 });
4363 } else {
4364 callFunc( oktellOptions.callback, getLoginErrorObj(1210) );
4365 self.trigger('connectError', getLoginErrorObj(1210) );
4366 disconnect(14);
4367 }
4368 });
4369 } else {
4370 callFunc( oktellOptions.callback, getLoginErrorObj(1206 ) );
4371 self.trigger('connectError', getLoginErrorObj(1206) );
4372 disconnect(11);
4373 }
4374 });
4375
4376
4377 } else {
4378 callFunc( oktellOptions.callback, getLoginErrorObj(1211) );
4379 self.trigger('connectError', getLoginErrorObj(1211) );
4380 disconnect(14);
4381 }
4382 });
4383 });
4384 server.on('errorConnection', function(data) {
4385 self.trigger('connectError', getErrorObj(1200) );
4386 callFunc( oktellOptions.callback, getErrorObj(1200) );
4387 });
4388 server.on('connectionClose', function() {
4389 if ( connectionClosedByUser ) {
4390 connectionClosedByUser = false;
4391 disconnect(13);
4392 } else if ( ! loginError ) {
4393 disconnect(12);
4394 }
4395 });
4396 server.multiConnect();
4397 if ( debugMode ) {
4398 oktellInfo.server = server;
4399 }
4400 };
4401
4402 createServer();
4403 };
4404 exportApi('connect', connect);
4405
4406 /**
4407 * disconnect from server
4408 * @param reason code or reason object
4409 * @param silent - trigger outside 'disconnect' event or not
4410 * @return {Boolean}
4411 */
4412 var disconnect = function( reason, silent) {
4413 oktellConnected(false);
4414 for (var i = 0; i < nativeEventsForBindAfterConnect.length; i++) {
4415 var obj = nativeEventsForBindAfterConnect[i];
4416 obj.binded = false;
4417 }
4418 if ( sipPhone && sipPhone.disconnect ) {
4419 sipPhone.disconnect();
4420 }
4421 if ( ! serverConnected() ) {
4422 if ( typeof reason == 'number' ) {
4423 reason = getDisconnectReasonObj(reason);
4424 }
4425 if ( ! silent ) {
4426 self.trigger('disconnect', reason);
4427 }
4428 } else {
4429 cookie(cookieSessionName, null);
4430 localStorage && (delete localStorage[cookieSessionName]);
4431 connectionClosedByUser = true;
4432 userStates.state(0);
4433 phone.state( phone.states.DISCONNECTED );
4434 sendOktell('logout');
4435 }
4436
4437 return true;
4438 };
4439
4440 var removeUserSession = function() {
4441 cookie(cookieSessionName, null);
4442 return true;
4443 };
4444 exportApi('removeUserSession', removeUserSession);
4445
4446 /**
4447 * Chanhe number plan's states
4448 */
4449 userStates.on('userStateChange', function(stateId) {
4450 setTimeout(function() { phone.loadStates(); }, 400);
4451 if ( stateId == 5 ) {
4452
4453 } else if ( stateId == 7 ) {
4454 phone.state( phone.states.DISCONNECTED );
4455 } else {
4456 phone.loadStates();
4457// phone.state( phone.states.READY );
4458 }
4459 });
4460
4461 /**
4462 * Subscribe to stuff on login
4463 */
4464 events.on('login', function() {
4465
4466 server.bindOktellEvent('linestatechanged', function(data) {
4467 setTimeout(function() {
4468 phone.loadStates();
4469 }, 500);
4470 });
4471
4472 server.bindOktellEvent('flashstatechanged', function(data) {
4473 setTimeout(function() {
4474 phone.loadStates();
4475 }, 500);
4476 });
4477
4478 server.bindOktellEvent('confcompositionchanged', function(data) {
4479 if ( data.eventinfo.conferenceid == phone.conferenceId() ) {
4480 phone.setConfAbonentList(data.eventinfo.competitorlist);
4481 phone.loadStates();
4482 }
4483 });
4484
4485 server.bindOktellEvent('phoneevent_acmcallstarted', function(data) {
4486 phone.loadStates(null, {
4487// sequence: phone.state() == phone.states.READY ? '': null,
4488 isAutoCall: true
4489 });
4490 });
4491
4492 server.bindOktellEvent('phoneevent_acmcallstopped', function(data) {
4493 setTimeout(function() {
4494 phone.loadStates();
4495 }, 700);
4496 });
4497
4498 server.bindOktellEvent('phoneevent_ringstarted', function(data) {
4499 phone.loadStates(function(result) {
4500 if ( phone.conferenceId() ) {
4501 phone.loadConferenceInfo();
4502 }
4503 }, false);
4504 });
4505
4506 server.bindOktellEvent('phoneevent_ringstopped', function(data) {
4507 phone.loadStates();
4508 });
4509
4510 server.bindOktellEvent('phoneevent_ivrstarted', function(data) {
4511 if ( data.isroutingivr === false ) {
4512 phone.notRoutingIvrState(true);
4513 } else if ( data.isroutingivr === true && phone.state() == phone.states.READY ) {
4514 phone.loadStates();
4515 }
4516 });
4517
4518 server.bindOktellEvent('phoneevent_commstarted', function(data) {
4519 phone.startTalkTimer(0);
4520 phone.currentSessionData.commStarted = true;
4521 if ( data.isconference ) {
4522 if ( phone.buildConfFromCommCallback ) {
4523 phone.isConfCreator(true);
4524 clearTimeout(phone.buildConfFromCommTimer);
4525 }
4526 phone.conferenceId(data.confid);
4527 phone.loadConferenceInfo(function() {
4528 phone.loadStates(function() {
4529 if ( phone.buildConfFromCommCallback ) {
4530 callFunc(phone.buildConfFromCommCallback, getSuccessObj());
4531 phone.buildConfFromCommCallback = undefined;
4532 }
4533 });
4534 });
4535 } else {
4536 setTimeout(function() {
4537 phone.loadStates(function() {});
4538 }, 700);
4539 }
4540 });
4541
4542 server.bindOktellEvent('phoneevent_commstopped', function(data) {
4543 phone.clearTalkTimer();
4544 phone.currentSessionData.commStopped = true;
4545 setTimeout(function() {
4546 phone.loadStates(function() {});
4547 }, 700);
4548 });
4549
4550 userStates.loadBreakReasons();
4551 });
4552
4553 //
4554 // API
4555 //
4556
4557 //self.loadPhoneStates = function(callback) { phone.loadStates(callback); };
4558
4559 /**
4560 * API disconnect from server
4561 * @param silent - trigger or not 'disconnect' event
4562 * @return {*}
4563 */
4564 self.disconnect = function(silent) {
4565 return disconnect( 13, silent);
4566 };
4567
4568 /**
4569 * API get current abonents list
4570 * @return {Object}
4571 */
4572 self.getAbonents = function() {
4573 return phone.getAbonents(true);
4574 };
4575
4576 /**
4577 * Call
4578 * @param number
4579 * @param callback
4580 */
4581 self.call = function( number, sequence, callback ) {
4582 phone.makeCall(number, false, typeof sequence == 'string' ? sequence : '', typeof sequence == 'function' ? sequence : callback);
4583 };
4584
4585 /**
4586 * API Subscribe to server events
4587 * @param eventName
4588 * @param callback
4589 */
4590 self.onNativeEvent = function( eventNames, callback) {
4591 bindOktellEvent(eventNames, callback);
4592 };
4593
4594 /**
4595 * API Unsubscribe from server events
4596 * @param eventName
4597 * @param callback
4598 */
4599 self.offNativeEvent = function( eventNames, callback) {
4600 unbindOktellEvent( eventNames, callback );
4601 };
4602
4603 /**
4604 * API Get information about current connection and user
4605 * @return {*}
4606 */
4607 self.getMyInfo = function() {
4608 return cloneObject(oktellInfo);
4609 }
4610
4611 /**
4612 * API Call in intercom mode
4613 * @param number
4614 * @param callback
4615 */
4616 self.intercom = function( number, callback ) {
4617 phone.makeCall(number, true, '', callback);
4618 };
4619
4620 /**
4621 * API Connect for wiretapping, or change mode for existing connection to wiretapping
4622 * @param target - phone number or userid
4623 * @param callback
4624 */
4625 self.ghostListen = function( target, callback) {
4626 phone.ghost(target, 'monitor', callback);
4627 };
4628 /**
4629 * API Connect for help , or change mode for existing connection to help
4630 * @param target
4631 * @param callback
4632 */
4633 self.ghostHelp = function( target, callback) {
4634 phone.ghost(target, 'help', callback);
4635 };
4636 /**
4637 * API Connect in conference mode, or change mode for existing connection to conference
4638 * @param target ##### ######## ### id ############
4639 * @param callback
4640 */
4641 self.ghostConference = function( target, callback) {
4642 phone.ghost(target, 'conference', callback);
4643 };
4644
4645 /**
4646 * API Get users
4647 * @return {Object}
4648 */
4649 self.getUsers = function() {
4650 var us = {}
4651 each(users, function(u) {
4652 us[u.id] = u;
4653 })
4654 return us;
4655 };
4656
4657 /**
4658 * API Get numbers
4659 * @return {Object}
4660 */
4661 self.getNumbers = function() {
4662 var nums = {}
4663 each(numbers, function(u) {
4664 nums[u.number] = u;
4665 });
4666 return nums;
4667 }
4668
4669 /**
4670 * API get lunch reasons
4671 */
4672 self.getLunchReasons = self.getBreakReasons = function() {
4673 return cloneObject(userStates.breakReasons) || {}
4674 }
4675
4676 self.getLog = function() {
4677 return logStr;
4678 }
4679
4680 exportApi('formatPhone', formatPhone, undefined);
4681
4682 self.inCallCenter = function() {
4683 return userStates.callCenterState();
4684 }
4685
4686 self.webphoneIsActive = function() {
4687 return sipPnoneActive;
4688 }
4689
4690 self.changePassword = function(newPass, oldPass, callback) {
4691 if ( ! (typeof newPass == 'string' && newPass) ) {
4692 callFunc(callback, getErrorObj(2802));
4693 } else {
4694 newPass = md5(utf8DecodePass(newPass));
4695 oldPass = md5(utf8DecodePass(oldPass));
4696 self.exec('changepassword', { newpwdmd5: newPass, oldpwdmd5: oldPass }, function(data) {
4697 if ( data.result ) {
4698 callFunc(callback, getSuccessObj({result: true}));
4699 } else if ( data.errormsg == 'old password is wrong' ) {
4700 callFunc(callback, getErrorObj(2801));
4701 } else {
4702 callFunc(callback, getErrorObj(2803));
4703 }
4704 });
4705 }
4706 }
4707
4708 self.config = function(config) {
4709 if ( ! config ) { return false; }
4710 if ( config.debugMode !== undefined ) {
4711 debugMode = Boolean(config.debugMode);
4712 }
4713 if ( config.queryDelayMin !== undefined ) {
4714 if ( server ) { server.setQueryDelayMin(config.queryDelayMin); } else { oktellOptions.queryDelayMin = config.queryDelayMin; }
4715 }
4716 if ( config.queryDelayMax !== undefined ) {
4717 if ( server ) { server.setQueryDelayMax(config.queryDelayMax); } else { oktellOptions.queryDelayMax = config.queryDelayMax; }
4718 }
4719 if ( config.queueInterval !== undefined && parseInt(config.queueInterval) ) {
4720 startQueueTimer(parseInt(config.queueInterval));
4721 }
4722 if ( config.queryTimeout !== undefined && parseInt(config.queryTimeout) ) {
4723 oktellOptions.queryTimeout = parseInt(config.queryTimeout);
4724 }
4725
4726 }
4727
4728 self.version = '1.7.2';
4729
4730 };
4731 extend( Oktell.prototype , Events );
4732
4733 return Oktell;
4734})();
4735 window.oktell = new Oktell;
4736 }
4737 Ext.define("Terrasoft.UsrOktellCtiProvider", {
4738 extend: "Terrasoft.BaseCtiProvider",
4739 singleton: true,
4740 deviceId: "",
4741 activeCall: null,
4742 consultCall: null,
4743 isaahs: true,
4744 iO: false,
4745 ossdp: 4055,
4746 connect: function(a) {
4747 initOktell();
4748 this.isaahs = (a.isSipAutoAnswerHeaderSupported !== false);
4749 this.iO = (a.isOperator !== false);
4750 this.subscribe();
4751 if(a.UseOktellVoice) {
4752 oktellVoice.createUserMedia(function(){
4753 oktell.connect({
4754 url: a.url,
4755 login: a.login,
4756 password: a.password,
4757 webSocketSwfLocation: a.webSocketSwfLocation,
4758 debugMode: a.debugMode,
4759 oktellVoice: oktellVoice
4760 })
4761 });
4762 } else {
4763 oktell.connect({
4764 url: a.url,
4765 login: a.login,
4766 password: a.password,
4767 debugMode: a.debugMode,
4768 webSocketSwfLocation: a.webSocketSwfLocation
4769 })
4770 }
4771 },
4772 subscribe: function() {
4773 oktell.on("connect", this.onConnect, this);
4774 oktell.on("connectError", this.onConnectError, this);
4775 oktell.on("disconnect", this.onDisconnect, this);
4776 oktell.on("statusChange", this.onStatusChange, this);
4777 oktell.on("ringStart", this.onRingStart, this);
4778 oktell.on("ringStop", this.onRingStop, this);
4779 oktell.on("backRingStart", this.onBackRingStart, this);
4780 oktell.on("backRingStop", this.onBackRingStop, this);
4781 oktell.on("callStart", this.onCallStart, this);
4782 oktell.on("callStop", this.onCallStop, this);
4783 oktell.on("talkStart", this.onTalkStart, this);
4784 oktell.on("talkStop", this.onTalkStop, this);
4785 oktell.on("holdAbonentLeave", this.onHoldAbonentLeave, this);
4786 oktell.on("holdAbonentEnter", this.onHoldAbonentEnter, this);
4787 oktell.on("holdStateChange", this.onHoldStateChange, this);
4788 oktell.on("stateChange", this.onCallStateChange, this);
4789 oktell.on("abonentsChange", this.onAbonentsChange, this);
4790 var a = this;
4791 oktell.onNativeEvent("flashstatechanged", function() {
4792 a.onFlashStateChanged.apply(a, arguments)
4793 });
4794 oktell.onNativeEvent("userstatechanged", function() {
4795 a.getstateoktell();
4796 a.onUserStateChanged.apply(a, arguments)
4797 })
4798 },
4799 getstateoktell: function () {
4800 if (!Terrasoft.CtiModel.get("CtiSettings")) {
4801 return;
4802 }
4803 var serviceDataSt = {
4804 login: Terrasoft.CtiModel.get("CtiSettings").connectionParams.login
4805 };
4806 ServiceHelper.callService("AlphaOperatorStateService", "AlphaGetOperatorStatus",
4807 function(response) {
4808 var status = JSON.parse(response.AlphaGetOperatorStatusResult);
4809 if (status.success) {
4810 switch (status.respon.UserStateCode) {
4811 case 0:
4812 Ext.fly("LineStatus").setHTML(status.respon.UserStateText);
4813 Ext.util.CSS.removeStyleSheet("statuscolor");
4814 Ext.util.CSS.createStyleSheet("#LineStatus{color:red}","statuscolor");
4815 $('#RingingName').remove();
4816 break;
4817 case 1:
4818 Ext.fly("LineStatus").setHTML(status.respon.UserStateText);
4819 Ext.util.CSS.removeStyleSheet("statuscolor");
4820 Ext.util.CSS.createStyleSheet("#LineStatus{color:green}","statuscolor");
4821 $('#RingingName').remove();
4822 break;
4823 case 2:
4824 Ext.fly("LineStatus").setHTML(status.respon.UserStateText);
4825 Ext.util.CSS.removeStyleSheet("statuscolor");
4826 Ext.util.CSS.createStyleSheet("#LineStatus{color:gray}","statuscolor");
4827 $('#RingingName').remove();
4828 break;
4829 case 3:
4830 Ext.fly("LineStatus").setHTML(status.respon.UserStateText);
4831 Ext.util.CSS.removeStyleSheet("statuscolor");
4832 Ext.util.CSS.createStyleSheet("#LineStatus{color:red}","statuscolor");
4833 $('#RingingName').remove();
4834 break;
4835
4836 case 5:
4837
4838 Ext.fly("LineStatus").setHTML(status.respon.UserStateText);
4839 Ext.util.CSS.removeStyleSheet("statuscolor");
4840 Ext.util.CSS.createStyleSheet("#LineStatus{color:red}","statuscolor");
4841 break;
4842
4843 case 6:
4844 Ext.fly("LineStatus").setHTML(status.respon.UserStateText);
4845 Ext.util.CSS.removeStyleSheet("statuscolor");
4846 Ext.util.CSS.createStyleSheet("#LineStatus{color:orange}","statuscolor");
4847 $('#RingingName').remove();
4848 break;
4849 case 7:
4850 Ext.fly("LineStatus").setHTML(status.respon.UserStateText);
4851 Ext.util.CSS.removeStyleSheet("statuscolor");
4852 Ext.util.CSS.createStyleSheet("#LineStatus{color:red}","statuscolor");
4853 $('#RingingName').remove();
4854 break;
4855 }
4856 } else {
4857 console.log(status);
4858 }
4859 }, serviceDataSt, this);
4860 },
4861 unsubscribe: function() {
4862 ["connect", "connectError", "disconnect", "statusChange", "ringStart", "ringStop", "callStart",
4863 "callStop", "talkStart", "talkStop", "holdAbonentLeave", "holdAbonentEnter", "holdStateChange"
4864 ].forEach(function(el){ oktell.off(el); });
4865 },
4866 gcid: function(a) {
4867 return a.chainId + ":" + a.phone
4868 },
4869 ecid: function(a) {
4870 if (Ext.isEmpty(a)) {
4871 return null
4872 }
4873 var b = a.split(":");
4874 if (b.length < 2) {
4875 return null
4876 }
4877 return b[0]
4878 },
4879 gosu: function(a) {
4880 var b = this.initialConfig.connectionConfig;
4881 var d = b.url;
4882 if (Ext.isEmpty(d)) {
4883 throw new Terrasoft.ArgumentNullOrEmptyException({
4884 argumentName: "connectionConfig.url"
4885 })
4886 }
4887 var c = "http";
4888 var e = d.split("://");
4889 if (e.length > 1) {
4890 if (e[0] === "wss") {
4891 c = "https"
4892 }
4893 d = e[1]
4894 }
4895 e = d.split(":");
4896 if (e.length > 1) {
4897 d = e[0]
4898 }
4899 var f = a || this.ossdp;
4900 var g = Ext.String.format("{0}://{1}:{2}", c, d, f);
4901 return g
4902 },
4903 createCall: function(a, b, d) {
4904 var c = Ext.create("Terrasoft.integration.telephony.Call");
4905 c.id = this.gcid(a);
4906 c.direction = b;
4907 c.deviceId = this.deviceId;
4908 c.callContext = a.name;
4909 if (b === Terrasoft.CallDirection.IN) {
4910 c.callerId = a.phone;
4911 c.calledId = this.deviceId
4912 } else {
4913 c.callerId = this.deviceId;
4914 c.calledId = a.phone
4915 }
4916 c.ctiProvider = this;
4917 c.timeStamp = new Date();
4918 c.callFeaturesSet = Terrasoft.CallFeaturesSet.NONE;
4919 if (d) {
4920 c.redirectingId = this.deviceId;
4921 c.redirectionId = b === Terrasoft.CallDirection.OUT ? c.calledId : c.callerId;
4922 this.consultCall = c
4923 } else {
4924 c.callFeaturesSet = 8;
4925 this.activeCall = c
4926 }
4927 if (b === Terrasoft.CallDirection.IN && this.isaahs) {
4928 c.callFeaturesSet |= 4
4929 }
4930 c.state = 1;
4931 this.updateCall(c, this.onUpdateCall);
4932 return c
4933 },
4934 finishCall: function(a) {
4935 this.log("finishCall");
4936 var b;
4937 if (Ext.isEmpty(a)) {
4938 b = this.activeCall;
4939 this.activeCall = null
4940 } else {
4941 if (!Ext.isEmpty(this.activeCall) && this.activeCall.id === a) {
4942 b = this.activeCall;
4943 this.activeCall = null
4944 } else {
4945 if (!Ext.isEmpty(this.consultCall) && this.consultCall.id === a) {
4946 b = this.consultCall;
4947 this.consultCall = null
4948 }
4949 }
4950 }
4951 if (Ext.isEmpty(b)) {
4952 this.fireEvent("lineStateChanged", {
4953 callFeaturesSet: 2
4954 });
4955 return
4956 }
4957 b.oldState = b.state;
4958 b.state = Terrasoft.GeneralizedCallState.NONE;
4959 b.callFeaturesSet = 2;
4960 b.timeStamp = new Date();
4961 this.fireEvent("callFinished", b);
4962 if (!Ext.isEmpty(this.activeCall)) {
4963 this.fireEvent("lineStateChanged", {
4964 callFeaturesSet: this.activeCall.callFeaturesSet
4965 })
4966 } else {
4967 if (!Ext.isEmpty(this.consultCall)) {
4968 this.activeCall = this.consultCall;
4969 this.consultCall = null
4970 } else {
4971 this.fireEvent("lineStateChanged", {
4972 callFeaturesSet: b.callFeaturesSet
4973 })
4974 }
4975 }
4976 this.updateCall(b, this.onUpdateCall)
4977 },
4978 queryAgentState: function() {
4979 var a = oktell.getStatus();
4980 this.fireEvent("agentStateChanged", {
4981 userState: a
4982 })
4983 },
4984 setCallCenterState: function(a) {
4985 oktell.exec("setuserstate", {
4986 oncallcenter: a
4987 })
4988 },
4989 initCallCenterState: function() {
4990 this.setCallCenterState(this.iO === true)
4991 },
4992 updateCall: function (a,b) {
4993 if(!Ext.isEmpty(a)){
4994 Terrasoft.AjaxProvider.request({
4995 url:"../ServiceModel/MsgUtilService.svc/UpdateCall",
4996 scope:this,
4997 callback:b,
4998 jsonData:a.serialize()
4999 })
5000 }
5001 },
5002 onUpdateCall: function(a, b, d) {
5003 var c = Terrasoft.decode(d.responseText);
5004 if (b && Terrasoft.isGUID(c)) {
5005 var e = Terrasoft.decode(a.jsonData);
5006 if (!Ext.isEmpty(this.activeCall) && this.activeCall.id === e.id) {
5007 e = this.activeCall
5008 } else if (!Ext.isEmpty(this.consultCall) && this.consultCall.id === e.id) {
5009 e = this.consultCall
5010 }
5011 e.databaseUId = c;
5012 this.fireEvent("callSaved", e)
5013 } else {
5014 this.fireEvent("rawMessage", "Update Call error");
5015 this.fireEvent("error", {
5016 internalErrorCode: null,
5017 data: d.responseText,
5018 source: "App server",
5019 errorType: 3
5020 })
5021 }
5022 },
5023 onConnect: function() {
5024 this.deviceId = oktell.getMyInfo().number;
5025 this.initCallCenterState();
5026 this.changeCallCentreState(true);
5027 //this.setWrapUpUserState(false);
5028 this.fireEvent("rawMessage", "Connected");
5029 this.fireEvent("initialized", this);
5030 if(!Ext.get("oktell-ringtone")){
5031 //this.initRingtone();
5032 }
5033 },
5034 onConnectError: function(a) {
5035 this.fireEvent("rawMessage", "onConnectError: " + Ext.encode(a));
5036 this.fireEvent("error", {
5037 internalErrorCode: a.errorCode,
5038 data: a.errorMessage,
5039 source: "Oktell server",
5040 errorType: a.errorCode == 1200 ? 5 : a.errorCode == 1202 ? 6 : 2
5041 })
5042 },
5043 onDisconnect: function(a) {
5044 this.fireEvent("rawMessage", "Disconnected");
5045 this.fireEvent("disconnected", a);
5046 this.unsubscribe()
5047 },
5048 onStatusChange: function(a, b) {
5049 this.fireEvent("rawMessage", "newStatus: " + a + " oldStatus: " + b);
5050 this.fireEvent("agentStateChanged", {
5051 userState: a
5052 })
5053 },
5054 onRingStart: function(a) {
5055 /*var ring = Ext.get('oktell-ringtone');
5056 if (ring && oktell.getState() == "ring") {
5057 ring.dom.play();
5058 }*/
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071 // START OF Alexandr Nikolaev CODE!!!!!///
5072 var idchain=a[0].chainId;
5073 if($('#ctiPanelVideoContainer').children().length==1){}else{
5074 $('#ctiPanelVideoContainer').prepend('<label id="RingingName" class="t-label t-label call-date" style="" title="" data-item-marker="RingingName"></label>');
5075 }
5076 // console.log(`Oktel Ringing abracadabra ${idchain}`);
5077 var serviceDataSt = {
5078 ChainId: idchain,
5079 login: Terrasoft.CtiModel.get("CtiSettings").connectionParams.login
5080
5081 };
5082 ServiceHelper.callService("AlphaOperatorStateService", "AlphaGetIdTaskByIdchain",
5083 function(response) {
5084 console.log(`Abra oktell task ${response.AlphaGetIdTaskByIdchainResult}`);
5085 response = JSON.parse(response.AlphaGetIdTaskByIdchainResult);
5086 var taskName = response.respon.TaskName;
5087
5088 Ext.fly("RingingName").setHTML(taskName);
5089
5090
5091 }, serviceDataSt, this);
5092
5093
5094
5095
5096
5097//END OF Alexandr Nikolaev CODE //
5098
5099
5100
5101 this.fireEvent("rawMessage", "onRingStart: " + Ext.encode(a));
5102 var b = this.createCall(a[0], Terrasoft.CallDirection.IN, false);
5103 this.fireEvent("callStarted", b);
5104 this.fireEvent("lineStateChanged", {
5105 callFeaturesSet: b.callFeaturesSet
5106 })
5107 },
5108 onRingStop: function(a) {
5109 /*var ring = Ext.get('oktell-ringtone');
5110 if (ring) {
5111 ring.dom.pause();
5112 }*/
5113
5114 this.fireEvent("rawMessage", "onRingStop: " + Ext.encode(a));
5115 if (Ext.isEmpty(this.activeCall)) {
5116 /*this.logError("onRingStop: ActiveCall is empty");
5117 throw new Terrasoft.NullOrEmptyException("ActiveCall is empty")*/
5118 }
5119 if (oktell.getState() === Terrasoft.OktellLineState.READY) {
5120 this.finishCall(this.gcid(a[0]))
5121 }
5122 },
5123 onBackRingStart: function(a) {
5124 this.fireEvent("rawMessage", "onBackRingStart: " + Ext.encode(a))
5125 },
5126 onBackRingStop: function(a) {
5127 this.fireEvent("rawMessage", "onBackRingStop: " + Ext.encode(a))
5128 },
5129 onCallStart: function(a) {
5130 this.fireEvent("rawMessage", "onCallStart: " + Ext.encode(a));
5131 var b = a[0];
5132 var d = false;
5133 var c = this.activeCall;
5134 if (!Ext.isEmpty(c) && ((b.phone !== c.callerId) && (b.phone !== c.calledId))) {
5135 d = true
5136 }
5137 var e = this.createCall(b, Terrasoft.CallDirection.OUT, d);
5138 this.fireEvent("callStarted", e);
5139 this.fireEvent("lineStateChanged", {
5140 callFeaturesSet: e.callFeaturesSet
5141 })
5142 },
5143 onCallStop: function(a) {
5144 this.fireEvent("rawMessage", "onCallStop: " + Ext.encode(a));
5145 if(this.activeCall) {
5146 this.onTalkStop(this.activeCall.id);
5147 }
5148 if (Ext.isEmpty(this.activeCall)) {
5149 /*var b = "ActiveCall is empty";
5150 this.logError("onCallStop: {0}", b);
5151 throw new Terrasoft.NullOrEmptyException(b)*/
5152 }
5153 var d = oktell.getState();
5154 var c;
5155 if (d === Terrasoft.OktellLineState.READY || d === Terrasoft.OktellLineState.RING) {
5156 c = this.gcid(a[0]);
5157 this.finishCall(c);
5158 }
5159 var e = oktell.getHoldInfo();
5160 if (d === Terrasoft.OktellLineState.READY && e.hasHold) {
5161 oktell.hold()
5162 }
5163 if (d === Terrasoft.OktellLineState.TALK && !e.hasHold) {
5164 c = this.gcid(a[0]);
5165 if (!Ext.isEmpty(this.consultCall) && (this.consultCall.id === c)) {
5166 this.finishCall(c)
5167 }
5168 }
5169 },
5170 onTalkStart: function(a) {
5171 this.fireEvent("rawMessage", "onTalkStart: " + Ext.encode(a));
5172 var b = this.gcid(a[0]);
5173 if (Ext.isEmpty(this.activeCall)) {
5174 this.onRingStart(a)
5175 } else {
5176 if (Ext.isEmpty(this.consultCall) && (b !== this.activeCall.id)) {
5177 this.onCallStart(a)
5178 }
5179 }
5180 var d = !Ext.isEmpty(this.activeCall);
5181 var c;
5182 if (d && this.activeCall.id === b) {
5183 c = this.activeCall
5184 } else {
5185 var consultCallChain = this.consultCall.id.split(":")[0];
5186 var bChain = b.split(":")[0];
5187 if (!Ext.isEmpty(this.consultCall) && consultCallChain === bChain) {
5188 c = this.consultCall;
5189 if (d) {
5190 this.activeCall.callFeaturesSet = 128
5191 }
5192 }
5193 }
5194 if (Ext.isEmpty(c)) {
5195 return
5196 }
5197 c.timeStamp = new Date();
5198 c.callFeaturesSet = 8 | 16 | 512 | 256 | 1024;
5199 c.oldState = c.state;
5200 c.state = 2;
5201 if (c.oldState === 1) {
5202 this.fireEvent("commutationStarted", c)
5203 }
5204 if (d) {
5205 this.fireEvent("lineStateChanged", {
5206 callFeaturesSet: this.activeCall.callFeaturesSet
5207 })
5208 }
5209 this.updateCall(c, this.onUpdateCall)
5210 },
5211 onTalkStop: function(a) {
5212 this.fireEvent("rawMessage", "onTalkStop: " + Ext.encode(a));
5213 var b = oktell.getState();
5214 var d = oktell.getHoldInfo();
5215 var c = a[0];
5216 var e = (!Ext.isEmpty(c)) ? this.gcid(c) : null;
5217 if (b === Terrasoft.OktellLineState.TALK) {
5218 if (!d.hasHold) {
5219 if (!Ext.isEmpty(this.consultCall) && this.consultCall.id === e) {
5220 this.finishCall(e)
5221 } else {
5222 if (!Ext.isEmpty(this.activeCall) && this.activeCall.id === e) {
5223 this.finishCall(e)
5224 }
5225 }
5226 }
5227 } else {
5228 if (b === Terrasoft.OktellLineState.READY) {
5229 if (!d.hasHold) {
5230 this.finishCall(e);
5231 if (!Ext.isEmpty(this.activeCall)) {
5232 this.finishCall()
5233 }
5234 }
5235 } else {
5236 if (b === Terrasoft.OktellLineState.CALL && !d.hasHold) {
5237 this.finishCall(e)
5238 } else {
5239 if (!Ext.isEmpty(this.activeCall)) {
5240 if (!d.hasHold) {
5241 this.finishCall(e)
5242 }
5243 } else {
5244 var f = "ActiveCall is empty";
5245 this.logError("onTalkStop: {0}", f);
5246 throw new Terrasoft.NullOrEmptyException(f)
5247 }
5248 }
5249 }
5250 }
5251 },
5252 onHoldAbonentLeave: function(a) {
5253 this.fireEvent("rawMessage", "onHoldAbonentLeave: " + Ext.encode(a))
5254 },
5255 onHoldAbonentEnter: function(a) {
5256 this.fireEvent("rawMessage", "onHoldAbonentEnter: " + Ext.encode(a))
5257 },
5258 onHoldStateChange: function(a) {
5259 this.fireEvent("rawMessage", "onHoldStateChange: " + Ext.encode(a));
5260 var b = this.activeCall;
5261 if (Ext.isEmpty(b)) {
5262 var d = "Holded activeCall is empty";
5263 this.logError("onHoldStateChange: {0}", d);
5264 return
5265 }
5266 b.timeStamp = new Date();
5267 if (a.hasHold) {
5268 if (b.state !== 3) {
5269 b.callFeaturesSet = 32;
5270 b.state = 3;
5271 this.fireEvent("hold", b)
5272 }
5273 } else {
5274 b.callFeaturesSet = 16 | 8 | 512 | 256;
5275 b.state = 2;
5276 this.fireEvent("unhold", b)
5277 }
5278 this.updateCall(b, this.onUpdateCall);
5279 this.fireEvent("lineStateChanged", {
5280 callFeaturesSet: b.callFeaturesSet
5281 })
5282 },
5283 onCallStateChange: function(a, b) {
5284 this.log("stateChange, newState = {0}, oldState= {1}", a, b)
5285 },
5286 onFlashStateChanged: function(a) {
5287 this.fireEvent("rawMessage", "onFlashStateChanged: " + Ext.encode(a));
5288 if (a.flashtypeid === 4) {
5289 var b;
5290 if (!Ext.isEmpty(this.activeCall) && this.activeCall.state === 3) {
5291 b = this.activeCall
5292 } else {
5293 if (!Ext.isEmpty(this.consultCall) && this.consultCall.state === 3) {
5294 b = this.consultCall
5295 }
5296 }
5297 if (!Ext.isEmpty(b)) {
5298 this.fireEvent("unhold", b);
5299 this.updateCall(b, this.onUpdateCall);
5300 this.finishCall(b.id)
5301 }
5302 }
5303 },
5304 onUserStateChanged: function(a) {
5305 this.fireEvent("rawMessage", "onUserStateChanged: " + Ext.encode(a));
5306 this.fireEvent("callCentreStateChanged", a.oncallcenter)
5307 },
5308 init: function() {
5309 this.callParent(arguments);
5310 Terrasoft.AjaxProvider.request({
5311 url: "../ServiceModel/MsgUtilService.svc/LogInMsgServer",
5312 scope: this,
5313 callback: function(a, b, d) {
5314 if (b && Terrasoft.isGUID(d.responseText.replace(/\"/g, ""))) {
5315 this.connect(this.initialConfig.connectionConfig)
5316 } else {
5317 this.fireEvent("rawMessage", "LogInMsgService error");
5318 this.fireEvent("error", {
5319 internalErrorCode: null,
5320 data: d.responseText,
5321 source: "App server",
5322 errorType: 6
5323 })
5324 }
5325 },
5326 jsonData: {
5327 LicInfoKeys: this.licInfoKeys,
5328 UserUId: Terrasoft.SysValue.CURRENT_USER.value
5329 }
5330 })
5331 },
5332 closeConnection: function() {
5333 oktell.disconnect()
5334 },
5335 makeCall: function(d) {
5336 var c = this;
5337 oktell.call(d, "user", function(a) {
5338 if (!a.result) {
5339 c.fireEvent("error", {
5340 internalErrorCode: a.errorCode,
5341 data: a.errorMessage,
5342 source: "oktell.call"
5343 })
5344 }
5345 })
5346 },
5347 answerCall: function() {
5348 var d = this;
5349 oktell.answer(function(a) {
5350 if (!a.result) {
5351 if (a.errorCode === 2902) {
5352 d.isaahs = false
5353 }
5354 d.fireEvent("error", {
5355 internalErrorCode: a.errorCode,
5356 data: a.errorMessage,
5357 source: "oktell.answer"
5358 })
5359 }
5360 })
5361 },
5362 holdCall: function() {
5363 oktell.hold()
5364 },
5365 dropCall: function(a) {
5366 var b = a.direction === Terrasoft.CallDirection.Outgoing ? a.callerId : a.calledId;
5367 oktell.endCall(b)
5368 },
5369 makeConsultCall: function(a, b) {
5370 oktell.call(b)
5371 },
5372 transferCall: function() {
5373 oktell.endCall()
5374 },
5375 cancelTransfer: function(a, b) {
5376 this.dropCall(b)
5377 },
5378 blindTransferCall: function(d, c) {
5379 var e = this;
5380 oktell.transfer(c, function(a) {
5381 if (!a.result) {
5382 e.fireEvent("error", {
5383 internalErrorCode: a.errorCode,
5384 data: a.errorMessage,
5385 source: "oktell.blindTransferCall"
5386 })
5387 }
5388 })
5389 },
5390 setUserState: function(a, b, d) {
5391 oktell.setStatus(a, false, b);
5392 if (Ext.isFunction(d)) {
5393 d.call(this)
5394 }
5395 },
5396 setWrapUpUserState: function(a, b) {
5397 var d = (a) ? 5 : 1;
5398 if (Ext.isFunction(b)) {
5399 var c = function() {
5400 oktell.offNativeEvent("userstatechanged", c);
5401 b.call(this)
5402 }.bind(this);
5403 oktell.onNativeEvent("userstatechanged", c)
5404 }
5405 oktell.exec("setuserstate", {
5406 userstateid: d
5407 })
5408 },
5409 queryUserState: function() {
5410 var a = oktell.getStatus();
5411 this.fireEvent("agentStateChanged", {
5412 userState: a
5413 })
5414 },
5415 sendDtmf: function(a, b) {
5416 oktell.dtmf(b)
5417 },
5418 queryActiveCallSnapshot: function() {},
5419 queryLineState: function() {},
5420 changeCallCentreState: function(a) {
5421 var b = (a) ? "entercallcenter" : "exitcallcenter";
5422 oktell.exec(b)
5423 },
5424 getCapabilities: function() {
5425 var a = 1 | 2 | 8 | 16 | 32 | 128 | 256 | 512 | 1024;
5426 if (this.isaahs) {
5427 a |= 4
5428 }
5429 var b = 1 | 2;
5430 return {
5431 callCapabilities: a,
5432 agentCapabilities: Terrasoft.AgentFeaturesSet.CAN_GET_CALL_RECORDS
5433 }
5434 },
5435 getLog: function() {
5436 return oktell.getLog()
5437 },
5438 getRecordLinks: function(f, g, i) {
5439 var j = this.ecid(f);
5440 if (!Ext.isEmpty(j)) {
5441 var h = this;
5442 oktell.exec("getpbxcalljournal", {
5443 filter: {
5444 idchain: j
5445 }
5446 }, function (d) {
5447 if (!d.result) {
5448 g.call(i || h, []);
5449 return
5450 }
5451 var c = h.gosu();
5452 var e = [];
5453 Terrasoft.each(d.data, function (a) {
5454 var b = a.recordlink;
5455 if (Ext.isEmpty(b)) {
5456 return
5457 }
5458 e.push(c + b)
5459 }, h);
5460 g.call(i || h, e)
5461 })
5462 }
5463 },
5464
5465 /**
5466 * @inheritdoc Terrasoft.BaseCtiProvider#queryCallRecords
5467 */
5468 queryCallRecords: function(callId, callback) {
5469 this.tmpCallback = callback;
5470 oktell.onNativeEvent('getpbxcalljournalresult', this.getLink.bind(this, callback));
5471 var id = callId.split(':')[0];
5472 if(id) {
5473 oktell.exec("getpbxcalljournal",{
5474 "filter":{
5475 "idchain": id
5476 }
5477 });
5478 }
5479 },
5480
5481 getLink: function(callback, data){
5482 if(data.data[0] && data.data[0].recordlink) {
5483 var link = oktell.getMyInfo().oktellWebServerLink + data.data[0].recordlink;
5484 oktell.exec('gettemphttppass', function(data){
5485 if (data.result && data.password) {
5486 var downloadLink = link + '?temppass=' + data.password;
5487 callback([downloadLink]);
5488 }
5489 oktell.offNativeEvent('getpbxcalljournalresult', this.getLink);
5490 }, this);
5491 }
5492 },
5493
5494 initRingtone: function () {
5495 var ringtone = document.createElement('audio');
5496 ringtone.id = 'oktell-ringtone';
5497 ringtone.src = '../ringtone.mp3';
5498 ringtone.preload = 'auto';
5499 ringtone.loop = true;
5500 ringtone.type = "audio/mp3";
5501 document.body.appendChild(ringtone);
5502
5503 },
5504
5505 makeConference: function(numbers, callback){
5506 oktell.conference(numbers, callback);
5507 },
5508
5509 onAbonentsChange: function(a) {
5510 var b = a.length;
5511 this.log("abonentsChange. Count = {0}", b);
5512 if ((a = this.activeCall) && 0 === b) {
5513 var b = oktell.getHoldInfo()
5514 , c = oktell.getState();
5515 if (!b.hasHold && c === Terrasoft.OktellLineState.READY)
5516 (b = this.consultCall) && this.finishCall(b.id),
5517 this.finishCall(a.id)
5518 }
5519
5520 },
5521
5522 muteAudio: function () {
5523 oktell.toogleMuteAudio();
5524 },
5525
5526 unMuteAudio: function () {
5527 oktell.toogleMuteAudio(false);
5528 }
5529 });
5530});