From f2630b5e71aea8a8480bf56b87e71711e3cdbb95 Mon Sep 17 00:00:00 2001 From: Eric Green Date: Wed, 10 Jan 2018 14:58:23 -0500 Subject: [PATCH] Revert "dist/ files for 0.9.1" This reverts commit 1d936d0db510e4d37e8d6228ec60b6604eebde50. --- dist/sip-0.9.1.js | 11930 ---------------------------------------- dist/sip-0.9.1.min.js | 38 - dist/sip.js | 11930 ---------------------------------------- dist/sip.min.js | 38 - 4 files changed, 23936 deletions(-) delete mode 100644 dist/sip-0.9.1.js delete mode 100644 dist/sip-0.9.1.min.js delete mode 100644 dist/sip.js delete mode 100644 dist/sip.min.js diff --git a/dist/sip-0.9.1.js b/dist/sip-0.9.1.js deleted file mode 100644 index 09e96fad6..000000000 --- a/dist/sip-0.9.1.js +++ /dev/null @@ -1,11930 +0,0 @@ -/*! - * - * SIP version 0.9.1 - * Copyright (c) 2014-2017 Junction Networks, Inc - * Homepage: https://sipjs.com - * License: https://sipjs.com/license/ - * - * - * ~~~SIP.js contains substantial portions of JsSIP under the following license~~~ - * Homepage: http://jssip.net - * Copyright (c) 2012-2013 José Luis Millán - Versatica - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * ~~~ end JsSIP license ~~~ - * - * - * - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["SIP"] = factory(); - else - root["SIP"] = factory(); -})(typeof self !== 'undefined' ? self : this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 1); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1,eval)("this"); -} catch(e) { - // This works if the window reference is available - if(typeof window === "object") - g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = __webpack_require__(2)(__webpack_require__(34)); - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * @name SIP - * @namespace - */ - - -module.exports = function (environment) { - - var pkg = __webpack_require__(3), - version = pkg.version, - title = pkg.title; - - var SIP = Object.defineProperties({}, { - version: { - get: function get() { - return version; - } - }, - name: { - get: function get() { - return title; - } - } - }); - - __webpack_require__(4)(SIP, environment); - SIP.LoggerFactory = __webpack_require__(5)(environment.console); - SIP.EventEmitter = __webpack_require__(6)(); - SIP.C = __webpack_require__(8)(SIP.name, SIP.version); - SIP.Exceptions = __webpack_require__(9); - SIP.Timers = __webpack_require__(10)(environment.timers); - SIP.Transport = environment.Transport(SIP, environment.WebSocket); - __webpack_require__(11)(SIP); - __webpack_require__(12)(SIP); - __webpack_require__(13)(SIP); - __webpack_require__(14)(SIP); - __webpack_require__(15)(SIP); - __webpack_require__(16)(SIP); - __webpack_require__(18)(SIP); - __webpack_require__(19)(SIP); - SIP.SessionDescriptionHandler = __webpack_require__(20)(SIP.EventEmitter); - __webpack_require__(21)(SIP); - __webpack_require__(22)(SIP); - __webpack_require__(23)(SIP); - __webpack_require__(25)(SIP); - __webpack_require__(26)(SIP, environment); - __webpack_require__(28)(SIP); - SIP.DigestAuthentication = __webpack_require__(29)(SIP.Utils); - SIP.Grammar = __webpack_require__(30)(SIP); - SIP.WebRTC = { - Modifiers: __webpack_require__(32)(SIP), - Simple: __webpack_require__(33)(SIP) - }; - - return SIP; -}; - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -module.exports = {"name":"sip.js","title":"SIP.js","description":"A simple, intuitive, and powerful JavaScript signaling library","version":"0.9.1","main":"dist/sip.min.js","browser":{"./src/environment.js":"./src/environment_browser.js"},"homepage":"https://sipjs.com","author":"OnSIP (https://sipjs.com/aboutus/)","contributors":[{"url":"https://github.com/onsip/SIP.js/blob/master/THANKS.md"}],"repository":{"type":"git","url":"https://github.com/onsip/SIP.js.git"},"keywords":["sip","websocket","webrtc","library","javascript"],"devDependencies":{"babel-core":"^6.26.0","babel-loader":"^7.1.2","babel-preset-env":"^1.6.1","eslint":"^4.9.0","jasmine-core":"^2.8.0","karma":"^1.7.1","karma-cli":"^1.0.1","karma-jasmine":"^1.1.0","karma-jasmine-html-reporter":"^0.2.2","karma-mocha-reporter":"^2.2.5","karma-phantomjs-launcher":"^1.0.4","karma-webpack":"^2.0.6","pegjs":"^0.10.0","pegjs-loader":"^0.5.4","uglifyjs-webpack-plugin":"^1.0.1","webpack":"^3.8.1"},"engines":{"node":">=4.0"},"license":"MIT","scripts":{"prebuild":"eslint src/*.js src/**/*.js","build":"webpack --progress && cp dist/sip.js dist/sip-$npm_package_version.js && cp dist/sip.min.js dist/sip-$npm_package_version.min.js","browserTest":"sleep 2 && open http://0.0.0.0:9876/debug.html & karma start --reporters kjhtml --no-single-run","commandLineTest":"karma start --reporters mocha --browsers PhantomJS --single-run","buildAndTest":"npm run build && npm run commandLineTest"},"dependencies":{"ws":"^1.0.1"},"optionalDependencies":{"promiscuous":"^0.6.0"}} - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview Utils - */ - -module.exports = function (SIP, environment) { - var Utils; - - Utils = { - - Promise: environment.Promise, - - defer: function defer() { - var deferred = {}; - deferred.promise = new Utils.Promise(function (resolve, reject) { - deferred.resolve = resolve; - deferred.reject = reject; - }); - return deferred; - }, - - reducePromises: function reducePromises(arr, val) { - return arr.reduce(function (acc, fn) { - acc = acc.then(fn); - return acc; - }, SIP.Utils.Promise.resolve(val)); - }, - - augment: function augment(object, constructor, args, override) { - var idx, proto; - - // Add public properties from constructor's prototype onto object - proto = constructor.prototype; - for (idx in proto) { - if (override || object[idx] === undefined) { - object[idx] = proto[idx]; - } - } - - // Construct the object as though it were just created by constructor - constructor.apply(object, args); - }, - - optionsOverride: function optionsOverride(options, winner, loser, isDeprecated, logger, defaultValue) { - if (isDeprecated && options[loser]) { - logger.warn(loser + ' is deprecated, please use ' + winner + ' instead'); - } - - if (options[winner] && options[loser]) { - logger.warn(winner + ' overriding ' + loser); - } - - options[winner] = options[winner] || options[loser] || defaultValue; - }, - - str_utf8_length: function str_utf8_length(string) { - return encodeURIComponent(string).replace(/%[A-F\d]{2}/g, 'U').length; - }, - - generateFakeSDP: function generateFakeSDP(body) { - if (!body) { - return; - } - - var start = body.indexOf('o='); - var end = body.indexOf('\r\n', start); - - return 'v=0\r\n' + body.slice(start, end) + '\r\ns=-\r\nt=0 0\r\nc=IN IP4 0.0.0.0'; - }, - - isFunction: function isFunction(fn) { - if (fn !== undefined) { - return Object.prototype.toString.call(fn) === '[object Function]'; - } else { - return false; - } - }, - - isDecimal: function isDecimal(num) { - return !isNaN(num) && parseFloat(num) === parseInt(num, 10); - }, - - createRandomToken: function createRandomToken(size, base) { - var i, - r, - token = ''; - - base = base || 32; - - for (i = 0; i < size; i++) { - r = Math.random() * base | 0; - token += r.toString(base); - } - - return token; - }, - - newTag: function newTag() { - return SIP.Utils.createRandomToken(SIP.UA.C.TAG_LENGTH); - }, - - // http://stackoverflow.com/users/109538/broofa - newUUID: function newUUID() { - var UUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, - v = c === 'x' ? r : r & 0x3 | 0x8; - return v.toString(16); - }); - - return UUID; - }, - - hostType: function hostType(host) { - if (!host) { - return; - } else { - host = SIP.Grammar.parse(host, 'host'); - if (host !== -1) { - return host.host_type; - } - } - }, - - /** - * Normalize SIP URI. - * NOTE: It does not allow a SIP URI without username. - * Accepts 'sip', 'sips' and 'tel' URIs and convert them into 'sip'. - * Detects the domain part (if given) and properly hex-escapes the user portion. - * If the user portion has only 'tel' number symbols the user portion is clean of 'tel' visual separators. - * @private - * @param {String} target - * @param {String} [domain] - */ - normalizeTarget: function normalizeTarget(target, domain) { - var uri, target_array, target_user, target_domain; - - // If no target is given then raise an error. - if (!target) { - return; - // If a SIP.URI instance is given then return it. - } else if (target instanceof SIP.URI) { - return target; - - // If a string is given split it by '@': - // - Last fragment is the desired domain. - // - Otherwise append the given domain argument. - } else if (typeof target === 'string') { - target_array = target.split('@'); - - switch (target_array.length) { - case 1: - if (!domain) { - return; - } - target_user = target; - target_domain = domain; - break; - case 2: - target_user = target_array[0]; - target_domain = target_array[1]; - break; - default: - target_user = target_array.slice(0, target_array.length - 1).join('@'); - target_domain = target_array[target_array.length - 1]; - } - - // Remove the URI scheme (if present). - target_user = target_user.replace(/^(sips?|tel):/i, ''); - - // Remove 'tel' visual separators if the user portion just contains 'tel' number symbols. - if (/^[\-\.\(\)]*\+?[0-9\-\.\(\)]+$/.test(target_user)) { - target_user = target_user.replace(/[\-\.\(\)]/g, ''); - } - - // Build the complete SIP URI. - target = SIP.C.SIP + ':' + SIP.Utils.escapeUser(target_user) + '@' + target_domain; - // Finally parse the resulting URI. - uri = SIP.URI.parse(target); - - return uri; - } else { - return; - } - }, - - /** - * Hex-escape a SIP URI user. - * @private - * @param {String} user - */ - escapeUser: function escapeUser(user) { - // Don't hex-escape ':' (%3A), '+' (%2B), '?' (%3F"), '/' (%2F). - return encodeURIComponent(decodeURIComponent(user)).replace(/%3A/ig, ':').replace(/%2B/ig, '+').replace(/%3F/ig, '?').replace(/%2F/ig, '/'); - }, - - headerize: function headerize(string) { - var exceptions = { - 'Call-Id': 'Call-ID', - 'Cseq': 'CSeq', - 'Min-Se': 'Min-SE', - 'Rack': 'RAck', - 'Rseq': 'RSeq', - 'Www-Authenticate': 'WWW-Authenticate' - }, - name = string.toLowerCase().replace(/_/g, '-').split('-'), - hname = '', - parts = name.length, - part; - - for (part = 0; part < parts; part++) { - if (part !== 0) { - hname += '-'; - } - hname += name[part].charAt(0).toUpperCase() + name[part].substring(1); - } - if (exceptions[hname]) { - hname = exceptions[hname]; - } - return hname; - }, - - sipErrorCause: function sipErrorCause(status_code) { - var cause; - - for (cause in SIP.C.SIP_ERROR_CAUSES) { - if (SIP.C.SIP_ERROR_CAUSES[cause].indexOf(status_code) !== -1) { - return SIP.C.causes[cause]; - } - } - - return SIP.C.causes.SIP_FAILURE_CODE; - }, - - getReasonPhrase: function getReasonPhrase(code, specific) { - return specific || SIP.C.REASON_PHRASE[code] || ''; - }, - - getReasonHeaderValue: function getReasonHeaderValue(code, reason) { - reason = SIP.Utils.getReasonPhrase(code, reason); - return 'SIP ;cause=' + code + ' ;text="' + reason + '"'; - }, - - getCancelReason: function getCancelReason(code, reason) { - if (code && code < 200 || code > 699) { - throw new TypeError('Invalid status_code: ' + code); - } else if (code) { - return SIP.Utils.getReasonHeaderValue(code, reason); - } - }, - - buildStatusLine: function buildStatusLine(code, reason) { - code = code || null; - reason = reason || null; - - // Validate code and reason values - if (!code || code < 100 || code > 699) { - throw new TypeError('Invalid status_code: ' + code); - } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) { - throw new TypeError('Invalid reason_phrase: ' + reason); - } - - reason = Utils.getReasonPhrase(code, reason); - - return 'SIP/2.0 ' + code + ' ' + reason + '\r\n'; - }, - - /** - * Generate a random Test-Net IP (http://tools.ietf.org/html/rfc5735) - * @private - */ - getRandomTestNetIP: function getRandomTestNetIP() { - function getOctet(from, to) { - return Math.floor(Math.random() * (to - from + 1) + from); - } - return '192.0.2.' + getOctet(1, 254); - }, - - // MD5 (Message-Digest Algorithm) http://www.webtoolkit.info - calculateMD5: function calculateMD5(string) { - function RotateLeft(lValue, iShiftBits) { - return lValue << iShiftBits | lValue >>> 32 - iShiftBits; - } - - function AddUnsigned(lX, lY) { - var lX4, lY4, lX8, lY8, lResult; - lX8 = lX & 0x80000000; - lY8 = lY & 0x80000000; - lX4 = lX & 0x40000000; - lY4 = lY & 0x40000000; - lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF); - if (lX4 & lY4) { - return lResult ^ 0x80000000 ^ lX8 ^ lY8; - } - if (lX4 | lY4) { - if (lResult & 0x40000000) { - return lResult ^ 0xC0000000 ^ lX8 ^ lY8; - } else { - return lResult ^ 0x40000000 ^ lX8 ^ lY8; - } - } else { - return lResult ^ lX8 ^ lY8; - } - } - - function F(x, y, z) { - return x & y | ~x & z; - } - - function G(x, y, z) { - return x & z | y & ~z; - } - - function H(x, y, z) { - return x ^ y ^ z; - } - - function I(x, y, z) { - return y ^ (x | ~z); - } - - function FF(a, b, c, d, x, s, ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - } - - function GG(a, b, c, d, x, s, ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - } - - function HH(a, b, c, d, x, s, ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - } - - function II(a, b, c, d, x, s, ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - } - - function ConvertToWordArray(string) { - var lWordCount; - var lMessageLength = string.length; - var lNumberOfWords_temp1 = lMessageLength + 8; - var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - lNumberOfWords_temp1 % 64) / 64; - var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16; - var lWordArray = Array(lNumberOfWords - 1); - var lBytePosition = 0; - var lByteCount = 0; - while (lByteCount < lMessageLength) { - lWordCount = (lByteCount - lByteCount % 4) / 4; - lBytePosition = lByteCount % 4 * 8; - lWordArray[lWordCount] = lWordArray[lWordCount] | string.charCodeAt(lByteCount) << lBytePosition; - lByteCount++; - } - lWordCount = (lByteCount - lByteCount % 4) / 4; - lBytePosition = lByteCount % 4 * 8; - lWordArray[lWordCount] = lWordArray[lWordCount] | 0x80 << lBytePosition; - lWordArray[lNumberOfWords - 2] = lMessageLength << 3; - lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; - return lWordArray; - } - - function WordToHex(lValue) { - var WordToHexValue = "", - WordToHexValue_temp = "", - lByte, - lCount; - for (lCount = 0; lCount <= 3; lCount++) { - lByte = lValue >>> lCount * 8 & 255; - WordToHexValue_temp = "0" + lByte.toString(16); - WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2); - } - return WordToHexValue; - } - - function Utf8Encode(string) { - string = string.replace(/\r\n/g, "\n"); - var utftext = ""; - - for (var n = 0; n < string.length; n++) { - var c = string.charCodeAt(n); - - if (c < 128) { - utftext += String.fromCharCode(c); - } else if (c > 127 && c < 2048) { - utftext += String.fromCharCode(c >> 6 | 192); - utftext += String.fromCharCode(c & 63 | 128); - } else { - utftext += String.fromCharCode(c >> 12 | 224); - utftext += String.fromCharCode(c >> 6 & 63 | 128); - utftext += String.fromCharCode(c & 63 | 128); - } - } - return utftext; - } - - var x = []; - var k, AA, BB, CC, DD, a, b, c, d; - var S11 = 7, - S12 = 12, - S13 = 17, - S14 = 22; - var S21 = 5, - S22 = 9, - S23 = 14, - S24 = 20; - var S31 = 4, - S32 = 11, - S33 = 16, - S34 = 23; - var S41 = 6, - S42 = 10, - S43 = 15, - S44 = 21; - - string = Utf8Encode(string); - - x = ConvertToWordArray(string); - - a = 0x67452301;b = 0xEFCDAB89;c = 0x98BADCFE;d = 0x10325476; - - for (k = 0; k < x.length; k += 16) { - AA = a;BB = b;CC = c;DD = d; - a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478); - d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756); - c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB); - b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE); - a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF); - d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A); - c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613); - b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501); - a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8); - d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF); - c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1); - b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE); - a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122); - d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193); - c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E); - b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821); - a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562); - d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340); - c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51); - b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA); - a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D); - d = GG(d, a, b, c, x[k + 10], S22, 0x2441453); - c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681); - b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8); - a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6); - d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6); - c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87); - b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED); - a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905); - d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8); - c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9); - b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A); - a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942); - d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681); - c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122); - b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C); - a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44); - d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9); - c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60); - b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70); - a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6); - d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA); - c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085); - b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05); - a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039); - d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5); - c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8); - b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665); - a = II(a, b, c, d, x[k + 0], S41, 0xF4292244); - d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97); - c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7); - b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039); - a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3); - d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92); - c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D); - b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1); - a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F); - d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0); - c = II(c, d, a, b, x[k + 6], S43, 0xA3014314); - b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1); - a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82); - d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235); - c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB); - b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391); - a = AddUnsigned(a, AA); - b = AddUnsigned(b, BB); - c = AddUnsigned(c, CC); - d = AddUnsigned(d, DD); - } - - var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d); - - return temp.toLowerCase(); - } - }; - - SIP.Utils = Utils; -}; - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var levels = { - 'error': 0, - 'warn': 1, - 'log': 2, - 'debug': 3 -}; - -module.exports = function (console) { - - var LoggerFactory = function LoggerFactory() { - var logger, - level = 2, - builtinEnabled = true, - connector = null; - - this.loggers = {}; - - logger = this.getLogger('sip.loggerfactory'); - - Object.defineProperties(this, { - builtinEnabled: { - get: function get() { - return builtinEnabled; - }, - set: function set(value) { - if (typeof value === 'boolean') { - builtinEnabled = value; - } else { - logger.error('invalid "builtinEnabled" parameter value: ' + JSON.stringify(value)); - } - } - }, - - level: { - get: function get() { - return level; - }, - set: function set(value) { - if (value >= 0 && value <= 3) { - level = value; - } else if (value > 3) { - level = 3; - } else if (levels.hasOwnProperty(value)) { - level = levels[value]; - } else { - logger.error('invalid "level" parameter value: ' + JSON.stringify(value)); - } - } - }, - - connector: { - get: function get() { - return connector; - }, - set: function set(value) { - if (value === null || value === "" || value === undefined) { - connector = null; - } else if (typeof value === 'function') { - connector = value; - } else { - logger.error('invalid "connector" parameter value: ' + JSON.stringify(value)); - } - } - } - }); - }; - - LoggerFactory.prototype.print = function (target, category, label, content) { - if (typeof content === 'string') { - var prefix = [new Date(), category]; - if (label) { - prefix.push(label); - } - content = prefix.concat(content).join(' | '); - } - target.call(console, content); - }; - - function Logger(logger, category, label) { - this.logger = logger; - this.category = category; - this.label = label; - } - - Object.keys(levels).forEach(function (targetName) { - Logger.prototype[targetName] = function (content) { - this.logger[targetName](this.category, this.label, content); - }; - - LoggerFactory.prototype[targetName] = function (category, label, content) { - if (this.level >= levels[targetName]) { - if (this.builtinEnabled) { - this.print(console[targetName], category, label, content); - } - - if (this.connector) { - this.connector(targetName, category, label, content); - } - } - }; - }); - - LoggerFactory.prototype.getLogger = function (category, label) { - var logger; - - if (label && this.level === 3) { - return new Logger(this, category, label); - } else if (this.loggers[category]) { - return this.loggers[category]; - } else { - logger = new Logger(this, category); - this.loggers[category] = logger; - return logger; - } - }; - - return LoggerFactory; -}; - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var NodeEventEmitter = __webpack_require__(7).EventEmitter; - -module.exports = function () { - - // Don't use `new SIP.EventEmitter()` for inheriting. - // Use Object.create(SIP.EventEmitter.prototoype); - function EventEmitter() { - NodeEventEmitter.call(this); - } - - EventEmitter.prototype = Object.create(NodeEventEmitter.prototype, { - constructor: { - value: EventEmitter, - enumerable: false, - writable: true, - configurable: true - } - }); - - return EventEmitter; -}; - -/***/ }), -/* 7 */ -/***/ (function(module, exports) { - -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } else { - // At least give some kind of context to the user - var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); - err.context = er; - throw err; - } - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - } else if (isObject(handler)) { - args = Array.prototype.slice.call(arguments, 1); - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - - if (isFunction(evlistener)) - return 1; - else if (evlistener) - return evlistener.length; - } - return 0; -}; - -EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); -}; - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isUndefined(arg) { - return arg === void 0; -} - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Constants - */ - -/** - * SIP Constants. - * @augments SIP - */ - -module.exports = function (name, version) { - return { - USER_AGENT: name + '/' + version, - - // SIP scheme - SIP: 'sip', - SIPS: 'sips', - - // End and Failure causes - causes: { - // Generic error causes - CONNECTION_ERROR: 'Connection Error', - REQUEST_TIMEOUT: 'Request Timeout', - SIP_FAILURE_CODE: 'SIP Failure Code', - INTERNAL_ERROR: 'Internal Error', - - // SIP error causes - BUSY: 'Busy', - REJECTED: 'Rejected', - REDIRECTED: 'Redirected', - UNAVAILABLE: 'Unavailable', - NOT_FOUND: 'Not Found', - ADDRESS_INCOMPLETE: 'Address Incomplete', - INCOMPATIBLE_SDP: 'Incompatible SDP', - AUTHENTICATION_ERROR: 'Authentication Error', - DIALOG_ERROR: 'Dialog Error', - - // Session error causes - WEBRTC_NOT_SUPPORTED: 'WebRTC Not Supported', - WEBRTC_ERROR: 'WebRTC Error', - CANCELED: 'Canceled', - NO_ANSWER: 'No Answer', - EXPIRES: 'Expires', - NO_ACK: 'No ACK', - NO_PRACK: 'No PRACK', - USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access', - BAD_MEDIA_DESCRIPTION: 'Bad Media Description', - RTP_TIMEOUT: 'RTP Timeout' - }, - - supported: { - UNSUPPORTED: 'none', - SUPPORTED: 'supported', - REQUIRED: 'required' - }, - - SIP_ERROR_CAUSES: { - REDIRECTED: [300, 301, 302, 305, 380], - BUSY: [486, 600], - REJECTED: [403, 603], - NOT_FOUND: [404, 604], - UNAVAILABLE: [480, 410, 408, 430], - ADDRESS_INCOMPLETE: [484], - INCOMPATIBLE_SDP: [488, 606], - AUTHENTICATION_ERROR: [401, 407] - }, - - // SIP Methods - ACK: 'ACK', - BYE: 'BYE', - CANCEL: 'CANCEL', - INFO: 'INFO', - INVITE: 'INVITE', - MESSAGE: 'MESSAGE', - NOTIFY: 'NOTIFY', - OPTIONS: 'OPTIONS', - REGISTER: 'REGISTER', - UPDATE: 'UPDATE', - SUBSCRIBE: 'SUBSCRIBE', - REFER: 'REFER', - PRACK: 'PRACK', - - /* SIP Response Reasons - * DOC: http://www.iana.org/assignments/sip-parameters - * Copied from https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/constants.rb#L7 - */ - REASON_PHRASE: { - 100: 'Trying', - 180: 'Ringing', - 181: 'Call Is Being Forwarded', - 182: 'Queued', - 183: 'Session Progress', - 199: 'Early Dialog Terminated', // draft-ietf-sipcore-199 - 200: 'OK', - 202: 'Accepted', // RFC 3265 - 204: 'No Notification', //RFC 5839 - 300: 'Multiple Choices', - 301: 'Moved Permanently', - 302: 'Moved Temporarily', - 305: 'Use Proxy', - 380: 'Alternative Service', - 400: 'Bad Request', - 401: 'Unauthorized', - 402: 'Payment Required', - 403: 'Forbidden', - 404: 'Not Found', - 405: 'Method Not Allowed', - 406: 'Not Acceptable', - 407: 'Proxy Authentication Required', - 408: 'Request Timeout', - 410: 'Gone', - 412: 'Conditional Request Failed', // RFC 3903 - 413: 'Request Entity Too Large', - 414: 'Request-URI Too Long', - 415: 'Unsupported Media Type', - 416: 'Unsupported URI Scheme', - 417: 'Unknown Resource-Priority', // RFC 4412 - 420: 'Bad Extension', - 421: 'Extension Required', - 422: 'Session Interval Too Small', // RFC 4028 - 423: 'Interval Too Brief', - 428: 'Use Identity Header', // RFC 4474 - 429: 'Provide Referrer Identity', // RFC 3892 - 430: 'Flow Failed', // RFC 5626 - 433: 'Anonymity Disallowed', // RFC 5079 - 436: 'Bad Identity-Info', // RFC 4474 - 437: 'Unsupported Certificate', // RFC 4744 - 438: 'Invalid Identity Header', // RFC 4744 - 439: 'First Hop Lacks Outbound Support', // RFC 5626 - 440: 'Max-Breadth Exceeded', // RFC 5393 - 469: 'Bad Info Package', // draft-ietf-sipcore-info-events - 470: 'Consent Needed', // RFC 5360 - 478: 'Unresolvable Destination', // Custom code copied from Kamailio. - 480: 'Temporarily Unavailable', - 481: 'Call/Transaction Does Not Exist', - 482: 'Loop Detected', - 483: 'Too Many Hops', - 484: 'Address Incomplete', - 485: 'Ambiguous', - 486: 'Busy Here', - 487: 'Request Terminated', - 488: 'Not Acceptable Here', - 489: 'Bad Event', // RFC 3265 - 491: 'Request Pending', - 493: 'Undecipherable', - 494: 'Security Agreement Required', // RFC 3329 - 500: 'Internal Server Error', - 501: 'Not Implemented', - 502: 'Bad Gateway', - 503: 'Service Unavailable', - 504: 'Server Time-out', - 505: 'Version Not Supported', - 513: 'Message Too Large', - 580: 'Precondition Failure', // RFC 3312 - 600: 'Busy Everywhere', - 603: 'Decline', - 604: 'Does Not Exist Anywhere', - 606: 'Not Acceptable' - }, - - /* SIP Option Tags - * DOC: http://www.iana.org/assignments/sip-parameters/sip-parameters.xhtml#sip-parameters-4 - */ - OPTION_TAGS: { - '100rel': true, // RFC 3262 - 199: true, // RFC 6228 - answermode: true, // RFC 5373 - 'early-session': true, // RFC 3959 - eventlist: true, // RFC 4662 - explicitsub: true, // RFC-ietf-sipcore-refer-explicit-subscription-03 - 'from-change': true, // RFC 4916 - 'geolocation-http': true, // RFC 6442 - 'geolocation-sip': true, // RFC 6442 - gin: true, // RFC 6140 - gruu: true, // RFC 5627 - histinfo: true, // RFC 7044 - ice: true, // RFC 5768 - join: true, // RFC 3911 - 'multiple-refer': true, // RFC 5368 - norefersub: true, // RFC 4488 - nosub: true, // RFC-ietf-sipcore-refer-explicit-subscription-03 - outbound: true, // RFC 5626 - path: true, // RFC 3327 - policy: true, // RFC 6794 - precondition: true, // RFC 3312 - pref: true, // RFC 3840 - privacy: true, // RFC 3323 - 'recipient-list-invite': true, // RFC 5366 - 'recipient-list-message': true, // RFC 5365 - 'recipient-list-subscribe': true, // RFC 5367 - replaces: true, // RFC 3891 - 'resource-priority': true, // RFC 4412 - 'sdp-anat': true, // RFC 4092 - 'sec-agree': true, // RFC 3329 - tdialog: true, // RFC 4538 - timer: true, // RFC 4028 - uui: true // RFC 7433 - } - }; -}; - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview Exceptions - */ - -/** - * SIP Exceptions. - * @augments SIP - */ - -module.exports = { - ConfigurationError: function () { - var exception = function exception(parameter, value) { - this.code = 1; - this.name = 'CONFIGURATION_ERROR'; - this.parameter = parameter; - this.value = value; - this.message = !this.value ? 'Missing parameter: ' + this.parameter : 'Invalid value ' + JSON.stringify(this.value) + ' for parameter "' + this.parameter + '"'; - }; - exception.prototype = new Error(); - return exception; - }(), - - InvalidStateError: function () { - var exception = function exception(status) { - this.code = 2; - this.name = 'INVALID_STATE_ERROR'; - this.status = status; - this.message = 'Invalid status: ' + status; - }; - exception.prototype = new Error(); - return exception; - }(), - - NotSupportedError: function () { - var exception = function exception(message) { - this.code = 3; - this.name = 'NOT_SUPPORTED_ERROR'; - this.message = message; - }; - exception.prototype = new Error(); - return exception; - }(), - - GetDescriptionError: function () { - var exception = function exception(message) { - this.code = 4; - this.name = 'GET_DESCRIPTION_ERROR'; - this.message = message; - }; - exception.prototype = new Error(); - return exception; - }(), - - RenegotiationError: function () { - var exception = function exception(message) { - this.code = 5; - this.name = 'RENEGOTIATION_ERROR'; - this.message = message; - }; - exception.prototype = new Error(); - return exception; - }() -}; - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP TIMERS - */ - -/** - * @augments SIP - */ - -var T1 = 500, - T2 = 4000, - T4 = 5000; -module.exports = function (timers) { - var Timers = { - T1: T1, - T2: T2, - T4: T4, - TIMER_B: 64 * T1, - TIMER_D: 0 * T1, - TIMER_F: 64 * T1, - TIMER_H: 64 * T1, - TIMER_I: 0 * T1, - TIMER_J: 0 * T1, - TIMER_K: 0 * T4, - TIMER_L: 64 * T1, - TIMER_M: 64 * T1, - TIMER_N: 64 * T1, - PROVISIONAL_RESPONSE_INTERVAL: 60000 // See RFC 3261 Section 13.3.1.1 - }; - - ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval'].forEach(function (name) { - // can't just use timers[name].bind(timers) since it bypasses jasmine's - // clock-mocking - Timers[name] = function () { - return timers[name].apply(timers, arguments); - }; - }); - - return Timers; -}; - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Message Parser - */ - -/** - * Extract and parse every header of a SIP message. - * @augments SIP - * @namespace - */ - -module.exports = function (SIP) { - var Parser; - - function getHeader(data, headerStart) { - var - // 'start' position of the header. - start = headerStart, - - // 'end' position of the header. - end = 0, - - // 'partial end' position of the header. - partialEnd = 0; - - //End of message. - if (data.substring(start, start + 2).match(/(^\r\n)/)) { - return -2; - } - - while (end === 0) { - // Partial End of Header. - partialEnd = data.indexOf('\r\n', start); - - // 'indexOf' returns -1 if the value to be found never occurs. - if (partialEnd === -1) { - return partialEnd; - } - - if (!data.substring(partialEnd + 2, partialEnd + 4).match(/(^\r\n)/) && data.charAt(partialEnd + 2).match(/(^\s+)/)) { - // Not the end of the message. Continue from the next position. - start = partialEnd + 2; - } else { - end = partialEnd; - } - } - - return end; - } - - function parseHeader(message, data, headerStart, headerEnd) { - var header, - idx, - length, - parsed, - hcolonIndex = data.indexOf(':', headerStart), - headerName = data.substring(headerStart, hcolonIndex).trim(), - headerValue = data.substring(hcolonIndex + 1, headerEnd).trim(); - - // If header-field is well-known, parse it. - switch (headerName.toLowerCase()) { - case 'via': - case 'v': - message.addHeader('via', headerValue); - if (message.getHeaders('via').length === 1) { - parsed = message.parseHeader('Via'); - if (parsed) { - message.via = parsed; - message.via_branch = parsed.branch; - } - } else { - parsed = 0; - } - break; - case 'from': - case 'f': - message.setHeader('from', headerValue); - parsed = message.parseHeader('from'); - if (parsed) { - message.from = parsed; - message.from_tag = parsed.getParam('tag'); - } - break; - case 'to': - case 't': - message.setHeader('to', headerValue); - parsed = message.parseHeader('to'); - if (parsed) { - message.to = parsed; - message.to_tag = parsed.getParam('tag'); - } - break; - case 'record-route': - parsed = SIP.Grammar.parse(headerValue, 'Record_Route'); - - if (parsed === -1) { - parsed = undefined; - break; - } - - length = parsed.length; - for (idx = 0; idx < length; idx++) { - header = parsed[idx]; - message.addHeader('record-route', headerValue.substring(header.position, header.offset)); - message.headers['Record-Route'][message.getHeaders('record-route').length - 1].parsed = header.parsed; - } - break; - case 'call-id': - case 'i': - message.setHeader('call-id', headerValue); - parsed = message.parseHeader('call-id'); - if (parsed) { - message.call_id = headerValue; - } - break; - case 'contact': - case 'm': - parsed = SIP.Grammar.parse(headerValue, 'Contact'); - - if (parsed === -1) { - parsed = undefined; - break; - } - - length = parsed.length; - for (idx = 0; idx < length; idx++) { - header = parsed[idx]; - message.addHeader('contact', headerValue.substring(header.position, header.offset)); - message.headers['Contact'][message.getHeaders('contact').length - 1].parsed = header.parsed; - } - break; - case 'content-length': - case 'l': - message.setHeader('content-length', headerValue); - parsed = message.parseHeader('content-length'); - break; - case 'content-type': - case 'c': - message.setHeader('content-type', headerValue); - parsed = message.parseHeader('content-type'); - break; - case 'cseq': - message.setHeader('cseq', headerValue); - parsed = message.parseHeader('cseq'); - if (parsed) { - message.cseq = parsed.value; - } - if (message instanceof SIP.IncomingResponse) { - message.method = parsed.method; - } - break; - case 'max-forwards': - message.setHeader('max-forwards', headerValue); - parsed = message.parseHeader('max-forwards'); - break; - case 'www-authenticate': - message.setHeader('www-authenticate', headerValue); - parsed = message.parseHeader('www-authenticate'); - break; - case 'proxy-authenticate': - message.setHeader('proxy-authenticate', headerValue); - parsed = message.parseHeader('proxy-authenticate'); - break; - case 'refer-to': - case 'r': - message.setHeader('refer-to', headerValue); - parsed = message.parseHeader('refer-to'); - if (parsed) { - message.refer_to = parsed; - } - break; - default: - // Do not parse this header. - message.setHeader(headerName, headerValue); - parsed = 0; - } - - if (parsed === undefined) { - return { - error: 'error parsing header "' + headerName + '"' - }; - } else { - return true; - } - } - - /** Parse SIP Message - * @function - * @param {String} message SIP message. - * @param {Object} logger object. - * @returns {SIP.IncomingRequest|SIP.IncomingResponse|undefined} - */ - Parser = {}; - Parser.parseMessage = function (data, ua) { - var message, - firstLine, - contentLength, - bodyStart, - parsed, - headerStart = 0, - headerEnd = data.indexOf('\r\n'), - logger = ua.getLogger('sip.parser'); - - if (headerEnd === -1) { - logger.warn('no CRLF found, not a SIP message, discarded'); - return; - } - - // Parse first line. Check if it is a Request or a Reply. - firstLine = data.substring(0, headerEnd); - parsed = SIP.Grammar.parse(firstLine, 'Request_Response'); - - if (parsed === -1) { - logger.warn('error parsing first line of SIP message: "' + firstLine + '"'); - return; - } else if (!parsed.status_code) { - message = new SIP.IncomingRequest(ua); - message.method = parsed.method; - message.ruri = parsed.uri; - } else { - message = new SIP.IncomingResponse(ua); - message.status_code = parsed.status_code; - message.reason_phrase = parsed.reason_phrase; - } - - message.data = data; - headerStart = headerEnd + 2; - - /* Loop over every line in data. Detect the end of each header and parse - * it or simply add to the headers collection. - */ - while (true) { - headerEnd = getHeader(data, headerStart); - - // The SIP message has normally finished. - if (headerEnd === -2) { - bodyStart = headerStart + 2; - break; - } - // data.indexOf returned -1 due to a malformed message. - else if (headerEnd === -1) { - logger.error('malformed message'); - return; - } - - parsed = parseHeader(message, data, headerStart, headerEnd); - - if (parsed !== true) { - logger.error(parsed.error); - return; - } - - headerStart = headerEnd + 2; - } - - /* RFC3261 18.3. - * If there are additional bytes in the transport packet - * beyond the end of the body, they MUST be discarded. - */ - if (message.hasHeader('content-length')) { - contentLength = message.getHeader('content-length'); - message.body = data.substr(bodyStart, contentLength); - } else { - message.body = data.substring(bodyStart); - } - - return message; - }; - - SIP.Parser = Parser; -}; - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Message - */ - -module.exports = function (SIP) { - var OutgoingRequest, IncomingMessage, IncomingRequest, IncomingResponse; - - function getSupportedHeader(request) { - var allowUnregistered = request.ua.configuration.hackAllowUnregisteredOptionTags; - var optionTags = []; - var optionTagSet = {}; - - if (request.method === SIP.C.REGISTER) { - optionTags.push('path', 'gruu'); - } else if (request.method === SIP.C.INVITE && (request.ua.contact.pub_gruu || request.ua.contact.temp_gruu)) { - optionTags.push('gruu'); - } - - if (request.ua.configuration.rel100 === SIP.C.supported.SUPPORTED) { - optionTags.push('100rel'); - } - if (request.ua.configuration.replaces === SIP.C.supported.SUPPORTED) { - optionTags.push('replaces'); - } - - optionTags.push('outbound'); - - optionTags = optionTags.concat(request.ua.configuration.extraSupported); - - optionTags = optionTags.filter(function (optionTag) { - var registered = SIP.C.OPTION_TAGS[optionTag]; - var unique = !optionTagSet[optionTag]; - optionTagSet[optionTag] = true; - return (registered || allowUnregistered) && unique; - }); - - return 'Supported: ' + optionTags.join(', ') + '\r\n'; - } - - /** - * @augments SIP - * @class Class for outgoing SIP request. - * @param {String} method request method - * @param {String} ruri request uri - * @param {SIP.UA} ua - * @param {Object} params parameters that will have priority over ua.configuration parameters: - *
- * - cseq, call_id, from_tag, from_uri, from_displayName, to_uri, to_tag, route_set - * @param {Object} [headers] extra headers - * @param {String} [body] - */ - OutgoingRequest = function OutgoingRequest(method, ruri, ua, params, extraHeaders, body) { - var to, from, call_id, cseq, to_uri, from_uri; - - params = params || {}; - - // Mandatory parameters check - if (!method || !ruri || !ua) { - return null; - } - - this.logger = ua.getLogger('sip.sipmessage'); - this.ua = ua; - this.headers = {}; - this.method = method; - this.ruri = ruri; - this.body = body; - this.extraHeaders = (extraHeaders || []).slice(); - this.statusCode = params.status_code; - this.reasonPhrase = params.reason_phrase; - - // Fill the Common SIP Request Headers - - // Route - if (params.route_set) { - this.setHeader('route', params.route_set); - } else if (ua.configuration.usePreloadedRoute) { - this.setHeader('route', ua.transport.server.sip_uri); - } - - // Via - // Empty Via header. Will be filled by the client transaction. - this.setHeader('via', ''); - - // Max-Forwards - this.setHeader('max-forwards', SIP.UA.C.MAX_FORWARDS); - - // To - to_uri = params.to_uri || ruri; - to = params.to_displayName || params.to_displayName === 0 ? '"' + params.to_displayName + '" ' : ''; - to += '<' + (to_uri && to_uri.toRaw ? to_uri.toRaw() : to_uri) + '>'; - to += params.to_tag ? ';tag=' + params.to_tag : ''; - this.to = new SIP.NameAddrHeader.parse(to); - this.setHeader('to', to); - - // From - from_uri = params.from_uri || ua.configuration.uri; - if (params.from_displayName || params.from_displayName === 0) { - from = '"' + params.from_displayName + '" '; - } else if (ua.configuration.displayName) { - from = '"' + ua.configuration.displayName + '" '; - } else { - from = ''; - } - from += '<' + (from_uri && from_uri.toRaw ? from_uri.toRaw() : from_uri) + '>;tag='; - from += params.from_tag || SIP.Utils.newTag(); - this.from = new SIP.NameAddrHeader.parse(from); - this.setHeader('from', from); - - // Call-ID - call_id = params.call_id || ua.configuration.sipjsId + SIP.Utils.createRandomToken(15); - this.call_id = call_id; - this.setHeader('call-id', call_id); - - // CSeq - cseq = params.cseq || Math.floor(Math.random() * 10000); - this.cseq = cseq; - this.setHeader('cseq', cseq + ' ' + method); - }; - - OutgoingRequest.prototype = { - /** - * Replace the the given header by the given value. - * @param {String} name header name - * @param {String | Array} value header value - */ - setHeader: function setHeader(name, value) { - this.headers[SIP.Utils.headerize(name)] = value instanceof Array ? value : [value]; - }, - - /** - * Get the value of the given header name at the given position. - * @param {String} name header name - * @returns {String|undefined} Returns the specified header, undefined if header doesn't exist. - */ - getHeader: function getHeader(name) { - var regexp, - idx, - length = this.extraHeaders.length, - header = this.headers[SIP.Utils.headerize(name)]; - - if (header) { - if (header[0]) { - return header[0]; - } - } else { - regexp = new RegExp('^\\s*' + name + '\\s*:', 'i'); - for (idx = 0; idx < length; idx++) { - header = this.extraHeaders[idx]; - if (regexp.test(header)) { - return header.substring(header.indexOf(':') + 1).trim(); - } - } - } - - return; - }, - - /** - * Get the header/s of the given name. - * @param {String} name header name - * @returns {Array} Array with all the headers of the specified name. - */ - getHeaders: function getHeaders(name) { - var idx, - length, - regexp, - header = this.headers[SIP.Utils.headerize(name)], - result = []; - - if (header) { - length = header.length; - for (idx = 0; idx < length; idx++) { - result.push(header[idx]); - } - return result; - } else { - length = this.extraHeaders.length; - regexp = new RegExp('^\\s*' + name + '\\s*:', 'i'); - for (idx = 0; idx < length; idx++) { - header = this.extraHeaders[idx]; - if (regexp.test(header)) { - result.push(header.substring(header.indexOf(':') + 1).trim()); - } - } - return result; - } - }, - - /** - * Verify the existence of the given header. - * @param {String} name header name - * @returns {boolean} true if header with given name exists, false otherwise - */ - hasHeader: function hasHeader(name) { - var regexp, - idx, - length = this.extraHeaders.length; - - if (this.headers[SIP.Utils.headerize(name)]) { - return true; - } else { - regexp = new RegExp('^\\s*' + name + '\\s*:', 'i'); - for (idx = 0; idx < length; idx++) { - if (regexp.test(this.extraHeaders[idx])) { - return true; - } - } - } - - return false; - }, - - toString: function toString() { - var msg = '', - header, - length, - idx; - - msg += this.method + ' ' + (this.ruri.toRaw ? this.ruri.toRaw() : this.ruri) + ' SIP/2.0\r\n'; - - for (header in this.headers) { - length = this.headers[header].length; - for (idx = 0; idx < length; idx++) { - msg += header + ': ' + this.headers[header][idx] + '\r\n'; - } - } - - length = this.extraHeaders.length; - for (idx = 0; idx < length; idx++) { - msg += this.extraHeaders[idx].trim() + '\r\n'; - } - - msg += getSupportedHeader(this); - msg += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n'; - - if (this.body) { - if (typeof this.body === 'string') { - length = SIP.Utils.str_utf8_length(this.body); - msg += 'Content-Length: ' + length + '\r\n\r\n'; - msg += this.body; - } else { - if (this.body.body && this.body.contentType) { - length = SIP.Utils.str_utf8_length(this.body.body); - msg += 'Content-Type: ' + this.body.contentType + '\r\n'; - msg += 'Content-Length: ' + length + '\r\n\r\n'; - msg += this.body.body; - } else { - msg += 'Content-Length: ' + 0 + '\r\n\r\n'; - } - } - } else { - msg += 'Content-Length: ' + 0 + '\r\n\r\n'; - } - - return msg; - } - }; - - /** - * @augments SIP - * @class Class for incoming SIP message. - */ - IncomingMessage = function IncomingMessage() { - this.data = null; - this.headers = null; - this.method = null; - this.via = null; - this.via_branch = null; - this.call_id = null; - this.cseq = null; - this.from = null; - this.from_tag = null; - this.to = null; - this.to_tag = null; - this.body = null; - }; - - IncomingMessage.prototype = { - /** - * Insert a header of the given name and value into the last position of the - * header array. - * @param {String} name header name - * @param {String} value header value - */ - addHeader: function addHeader(name, value) { - var header = { raw: value }; - - name = SIP.Utils.headerize(name); - - if (this.headers[name]) { - this.headers[name].push(header); - } else { - this.headers[name] = [header]; - } - }, - - /** - * Get the value of the given header name at the given position. - * @param {String} name header name - * @returns {String|undefined} Returns the specified header, null if header doesn't exist. - */ - getHeader: function getHeader(name) { - var header = this.headers[SIP.Utils.headerize(name)]; - - if (header) { - if (header[0]) { - return header[0].raw; - } - } else { - return; - } - }, - - /** - * Get the header/s of the given name. - * @param {String} name header name - * @returns {Array} Array with all the headers of the specified name. - */ - getHeaders: function getHeaders(name) { - var idx, - length, - header = this.headers[SIP.Utils.headerize(name)], - result = []; - - if (!header) { - return []; - } - - length = header.length; - for (idx = 0; idx < length; idx++) { - result.push(header[idx].raw); - } - - return result; - }, - - /** - * Verify the existence of the given header. - * @param {String} name header name - * @returns {boolean} true if header with given name exists, false otherwise - */ - hasHeader: function hasHeader(name) { - return this.headers[SIP.Utils.headerize(name)] ? true : false; - }, - - /** - * Parse the given header on the given index. - * @param {String} name header name - * @param {Number} [idx=0] header index - * @returns {Object|undefined} Parsed header object, undefined if the header is not present or in case of a parsing error. - */ - parseHeader: function parseHeader(name, idx) { - var header, value, parsed; - - name = SIP.Utils.headerize(name); - - idx = idx || 0; - - if (!this.headers[name]) { - this.logger.log('header "' + name + '" not present'); - return; - } else if (idx >= this.headers[name].length) { - this.logger.log('not so many "' + name + '" headers present'); - return; - } - - header = this.headers[name][idx]; - value = header.raw; - - if (header.parsed) { - return header.parsed; - } - - //substitute '-' by '_' for grammar rule matching. - parsed = SIP.Grammar.parse(value, name.replace(/-/g, '_')); - - if (parsed === -1) { - this.headers[name].splice(idx, 1); //delete from headers - this.logger.warn('error parsing "' + name + '" header field with value "' + value + '"'); - return; - } else { - header.parsed = parsed; - return parsed; - } - }, - - /** - * Message Header attribute selector. Alias of parseHeader. - * @param {String} name header name - * @param {Number} [idx=0] header index - * @returns {Object|undefined} Parsed header object, undefined if the header is not present or in case of a parsing error. - * - * @example - * message.s('via',3).port - */ - s: function s(name, idx) { - return this.parseHeader(name, idx); - }, - - /** - * Replace the value of the given header by the value. - * @param {String} name header name - * @param {String} value header value - */ - setHeader: function setHeader(name, value) { - var header = { raw: value }; - this.headers[SIP.Utils.headerize(name)] = [header]; - }, - - toString: function toString() { - return this.data; - } - }; - - /** - * @augments IncomingMessage - * @class Class for incoming SIP request. - */ - IncomingRequest = function IncomingRequest(ua) { - this.logger = ua.getLogger('sip.sipmessage'); - this.ua = ua; - this.headers = {}; - this.ruri = null; - this.transport = null; - this.server_transaction = null; - }; - IncomingRequest.prototype = new IncomingMessage(); - - /** - * Stateful reply. - * @param {Number} code status code - * @param {String} reason reason phrase - * @param {Object} headers extra headers - * @param {String} body body - * @param {Function} [onSuccess] onSuccess callback - * @param {Function} [onFailure] onFailure callback - */ - // TODO: Get rid of callbacks and make promise based - IncomingRequest.prototype.reply = function (code, reason, extraHeaders, body, onSuccess, onFailure) { - var rr, - vias, - length, - idx, - response, - to = this.getHeader('To'), - r = 0, - v = 0; - - response = SIP.Utils.buildStatusLine(code, reason); - extraHeaders = (extraHeaders || []).slice(); - - if (this.method === SIP.C.INVITE && code > 100 && code <= 200) { - rr = this.getHeaders('record-route'); - length = rr.length; - - for (r; r < length; r++) { - response += 'Record-Route: ' + rr[r] + '\r\n'; - } - } - - vias = this.getHeaders('via'); - length = vias.length; - - for (v; v < length; v++) { - response += 'Via: ' + vias[v] + '\r\n'; - } - - if (!this.to_tag && code > 100) { - to += ';tag=' + SIP.Utils.newTag(); - } else if (this.to_tag && !this.s('to').hasParam('tag')) { - to += ';tag=' + this.to_tag; - } - - response += 'To: ' + to + '\r\n'; - response += 'From: ' + this.getHeader('From') + '\r\n'; - response += 'Call-ID: ' + this.call_id + '\r\n'; - response += 'CSeq: ' + this.cseq + ' ' + this.method + '\r\n'; - - length = extraHeaders.length; - for (idx = 0; idx < length; idx++) { - response += extraHeaders[idx].trim() + '\r\n'; - } - - response += getSupportedHeader(this); - response += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n'; - - if (body) { - if (typeof body === 'string') { - length = SIP.Utils.str_utf8_length(body); - response += 'Content-Type: application/sdp\r\n'; - response += 'Content-Length: ' + length + '\r\n\r\n'; - response += body; - } else { - if (body.body && body.contentType) { - length = SIP.Utils.str_utf8_length(body.body); - response += 'Content-Type: ' + body.contentType + '\r\n'; - response += 'Content-Length: ' + length + '\r\n\r\n'; - response += body.body; - } else { - response += 'Content-Length: ' + 0 + '\r\n\r\n'; - } - } - } else { - response += 'Content-Length: ' + 0 + '\r\n\r\n'; - } - - this.server_transaction.receiveResponse(code, response).then(onSuccess, onFailure); - - return response; - }; - - /** - * Stateless reply. - * @param {Number} code status code - * @param {String} reason reason phrase - */ - IncomingRequest.prototype.reply_sl = function (code, reason) { - var to, - response, - v = 0, - vias = this.getHeaders('via'), - length = vias.length; - - response = SIP.Utils.buildStatusLine(code, reason); - - for (v; v < length; v++) { - response += 'Via: ' + vias[v] + '\r\n'; - } - - to = this.getHeader('To'); - - if (!this.to_tag && code > 100) { - to += ';tag=' + SIP.Utils.newTag(); - } else if (this.to_tag && !this.s('to').hasParam('tag')) { - to += ';tag=' + this.to_tag; - } - - response += 'To: ' + to + '\r\n'; - response += 'From: ' + this.getHeader('From') + '\r\n'; - response += 'Call-ID: ' + this.call_id + '\r\n'; - response += 'CSeq: ' + this.cseq + ' ' + this.method + '\r\n'; - response += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n'; - response += 'Content-Length: ' + 0 + '\r\n\r\n'; - - this.transport.send(response); - }; - - /** - * @augments IncomingMessage - * @class Class for incoming SIP response. - */ - IncomingResponse = function IncomingResponse(ua) { - this.logger = ua.getLogger('sip.sipmessage'); - this.headers = {}; - this.status_code = null; - this.reason_phrase = null; - }; - IncomingResponse.prototype = new IncomingMessage(); - - SIP.OutgoingRequest = OutgoingRequest; - SIP.IncomingRequest = IncomingRequest; - SIP.IncomingResponse = IncomingResponse; -}; - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP URI - */ - -/** - * @augments SIP - * @class Class creating a SIP URI. - * - * @param {String} [scheme] - * @param {String} [user] - * @param {String} host - * @param {String} [port] - * @param {Object} [parameters] - * @param {Object} [headers] - * - */ - -module.exports = function (SIP) { - var URI; - - URI = function URI(scheme, user, host, port, parameters, headers) { - var param, header, raw, normal; - - // Checks - if (!host) { - throw new TypeError('missing or invalid "host" parameter'); - } - - // Initialize parameters - scheme = scheme || SIP.C.SIP; - this.parameters = {}; - this.headers = {}; - - for (param in parameters) { - this.setParam(param, parameters[param]); - } - - for (header in headers) { - this.setHeader(header, headers[header]); - } - - // Raw URI - raw = { - scheme: scheme, - user: user, - host: host, - port: port - }; - - // Normalized URI - normal = { - scheme: scheme.toLowerCase(), - user: user, - host: host.toLowerCase(), - port: port - }; - - Object.defineProperties(this, { - _normal: { - get: function get() { - return normal; - } - }, - - _raw: { - get: function get() { - return raw; - } - }, - - scheme: { - get: function get() { - return normal.scheme; - }, - set: function set(value) { - raw.scheme = value; - normal.scheme = value.toLowerCase(); - } - }, - - user: { - get: function get() { - return normal.user; - }, - set: function set(value) { - normal.user = raw.user = value; - } - }, - - host: { - get: function get() { - return normal.host; - }, - set: function set(value) { - raw.host = value; - normal.host = value.toLowerCase(); - } - }, - - aor: { - get: function get() { - return normal.user + '@' + normal.host; - } - }, - - port: { - get: function get() { - return normal.port; - }, - set: function set(value) { - normal.port = raw.port = value === 0 ? value : parseInt(value, 10) || null; - } - } - }); - }; - - URI.prototype = { - setParam: function setParam(key, value) { - if (key) { - this.parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString().toLowerCase(); - } - }, - - getParam: function getParam(key) { - if (key) { - return this.parameters[key.toLowerCase()]; - } - }, - - hasParam: function hasParam(key) { - if (key) { - return this.parameters.hasOwnProperty(key.toLowerCase()) && true || false; - } - }, - - deleteParam: function deleteParam(parameter) { - var value; - parameter = parameter.toLowerCase(); - if (this.parameters.hasOwnProperty(parameter)) { - value = this.parameters[parameter]; - delete this.parameters[parameter]; - return value; - } - }, - - clearParams: function clearParams() { - this.parameters = {}; - }, - - setHeader: function setHeader(name, value) { - this.headers[SIP.Utils.headerize(name)] = value instanceof Array ? value : [value]; - }, - - getHeader: function getHeader(name) { - if (name) { - return this.headers[SIP.Utils.headerize(name)]; - } - }, - - hasHeader: function hasHeader(name) { - if (name) { - return this.headers.hasOwnProperty(SIP.Utils.headerize(name)) && true || false; - } - }, - - deleteHeader: function deleteHeader(header) { - var value; - header = SIP.Utils.headerize(header); - if (this.headers.hasOwnProperty(header)) { - value = this.headers[header]; - delete this.headers[header]; - return value; - } - }, - - clearHeaders: function clearHeaders() { - this.headers = {}; - }, - - clone: function clone() { - return new URI(this._raw.scheme, this._raw.user, this._raw.host, this._raw.port, JSON.parse(JSON.stringify(this.parameters)), JSON.parse(JSON.stringify(this.headers))); - }, - - toRaw: function toRaw() { - return this._toString(this._raw); - }, - - toString: function toString() { - return this._toString(this._normal); - }, - - _toString: function _toString(uri) { - var header, - parameter, - idx, - uriString, - headers = []; - - uriString = uri.scheme + ':'; - // add slashes if it's not a sip(s) URI - if (!uri.scheme.toLowerCase().match("^sips?$")) { - uriString += "//"; - } - if (uri.user) { - uriString += SIP.Utils.escapeUser(uri.user) + '@'; - } - uriString += uri.host; - if (uri.port || uri.port === 0) { - uriString += ':' + uri.port; - } - - for (parameter in this.parameters) { - uriString += ';' + parameter; - - if (this.parameters[parameter] !== null) { - uriString += '=' + this.parameters[parameter]; - } - } - - for (header in this.headers) { - for (idx in this.headers[header]) { - headers.push(header + '=' + this.headers[header][idx]); - } - } - - if (headers.length > 0) { - uriString += '?' + headers.join('&'); - } - - return uriString; - } - }; - - /** - * Parse the given string and returns a SIP.URI instance or undefined if - * it is an invalid URI. - * @public - * @param {String} uri - */ - URI.parse = function (uri) { - uri = SIP.Grammar.parse(uri, 'SIP_URI'); - - if (uri !== -1) { - return uri; - } else { - return undefined; - } - }; - - SIP.URI = URI; -}; - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP NameAddrHeader - */ - -/** - * @augments SIP - * @class Class creating a Name Address SIP header. - * - * @param {SIP.URI} uri - * @param {String} [displayName] - * @param {Object} [parameters] - * - */ - -module.exports = function (SIP) { - var NameAddrHeader; - - NameAddrHeader = function NameAddrHeader(uri, displayName, parameters) { - var param; - - // Checks - if (!uri || !(uri instanceof SIP.URI)) { - throw new TypeError('missing or invalid "uri" parameter'); - } - - // Initialize parameters - this.uri = uri; - this.parameters = {}; - - for (param in parameters) { - this.setParam(param, parameters[param]); - } - - Object.defineProperties(this, { - friendlyName: { - get: function get() { - return this.displayName || uri.aor; - } - }, - - displayName: { - get: function get() { - return displayName; - }, - set: function set(value) { - displayName = value === 0 ? '0' : value; - } - } - }); - }; - NameAddrHeader.prototype = { - setParam: function setParam(key, value) { - if (key) { - this.parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString(); - } - }, - getParam: SIP.URI.prototype.getParam, - hasParam: SIP.URI.prototype.hasParam, - deleteParam: SIP.URI.prototype.deleteParam, - clearParams: SIP.URI.prototype.clearParams, - - clone: function clone() { - return new NameAddrHeader(this.uri.clone(), this.displayName, JSON.parse(JSON.stringify(this.parameters))); - }, - - toString: function toString() { - var body, parameter; - - body = this.displayName || this.displayName === 0 ? '"' + this.displayName + '" ' : ''; - body += '<' + this.uri.toString() + '>'; - - for (parameter in this.parameters) { - body += ';' + parameter; - - if (this.parameters[parameter] !== null) { - body += '=' + this.parameters[parameter]; - } - } - - return body; - } - }; - - /** - * Parse the given string and returns a SIP.NameAddrHeader instance or undefined if - * it is an invalid NameAddrHeader. - * @public - * @param {String} name_addr_header - */ - NameAddrHeader.parse = function (name_addr_header) { - name_addr_header = SIP.Grammar.parse(name_addr_header, 'Name_Addr_Header'); - - if (name_addr_header !== -1) { - return name_addr_header; - } else { - return undefined; - } - }; - - SIP.NameAddrHeader = NameAddrHeader; -}; - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Transactions - */ - -/** - * SIP Transactions module. - * @augments SIP - */ - -module.exports = function (SIP) { - var C = { - // Transaction states - STATUS_TRYING: 1, - STATUS_PROCEEDING: 2, - STATUS_CALLING: 3, - STATUS_ACCEPTED: 4, - STATUS_COMPLETED: 5, - STATUS_TERMINATED: 6, - STATUS_CONFIRMED: 7, - - // Transaction types - NON_INVITE_CLIENT: 'nict', - NON_INVITE_SERVER: 'nist', - INVITE_CLIENT: 'ict', - INVITE_SERVER: 'ist' - }; - - function buildViaHeader(request_sender, transport, id) { - var via; - via = 'SIP/2.0/' + (request_sender.ua.configuration.hackViaTcp ? 'TCP' : transport.server.scheme); - via += ' ' + request_sender.ua.configuration.viaHost + ';branch=' + id; - if (request_sender.ua.configuration.forceRport) { - via += ';rport'; - } - return via; - } - - /** - * @augments SIP.Transactions - * @class Non Invite Client Transaction - * @param {SIP.RequestSender} request_sender - * @param {SIP.OutgoingRequest} request - * @param {SIP.Transport} transport - */ - var NonInviteClientTransaction = function NonInviteClientTransaction(request_sender, request, transport) { - var via; - - this.type = C.NON_INVITE_CLIENT; - this.transport = transport; - this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000); - this.request_sender = request_sender; - this.request = request; - - this.logger = request_sender.ua.getLogger('sip.transaction.nict', this.id); - - via = buildViaHeader(request_sender, transport, this.id); - this.request.setHeader('via', via); - - this.request_sender.ua.newTransaction(this); - }; - NonInviteClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - NonInviteClientTransaction.prototype.stateChanged = function (state) { - this.state = state; - this.emit('stateChanged'); - }; - - NonInviteClientTransaction.prototype.send = function () { - var tr = this; - - this.stateChanged(C.STATUS_TRYING); - this.F = SIP.Timers.setTimeout(tr.timer_F.bind(tr), SIP.Timers.TIMER_F); - - if (!this.transport.send(this.request)) { - this.onTransportError(); - } - }; - - NonInviteClientTransaction.prototype.onTransportError = function () { - this.logger.log('transport error occurred, deleting non-INVITE client transaction ' + this.id); - SIP.Timers.clearTimeout(this.F); - SIP.Timers.clearTimeout(this.K); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - this.request_sender.onTransportError(); - }; - - NonInviteClientTransaction.prototype.timer_F = function () { - this.logger.debug('Timer F expired for non-INVITE client transaction ' + this.id); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - this.request_sender.onRequestTimeout(); - }; - - NonInviteClientTransaction.prototype.timer_K = function () { - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - }; - - NonInviteClientTransaction.prototype.receiveResponse = function (response) { - var tr = this, - status_code = response.status_code; - - if (status_code < 200) { - switch (this.state) { - case C.STATUS_TRYING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_PROCEEDING); - this.request_sender.receiveResponse(response); - break; - } - } else { - switch (this.state) { - case C.STATUS_TRYING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_COMPLETED); - SIP.Timers.clearTimeout(this.F); - - if (status_code === 408) { - this.request_sender.onRequestTimeout(); - } else { - this.request_sender.receiveResponse(response); - } - - this.K = SIP.Timers.setTimeout(tr.timer_K.bind(tr), SIP.Timers.TIMER_K); - break; - case C.STATUS_COMPLETED: - break; - } - } - }; - - /** - * @augments SIP.Transactions - * @class Invite Client Transaction - * @param {SIP.RequestSender} request_sender - * @param {SIP.OutgoingRequest} request - * @param {SIP.Transport} transport - */ - var InviteClientTransaction = function InviteClientTransaction(request_sender, request, transport) { - var via, - tr = this; - - this.type = C.INVITE_CLIENT; - this.transport = transport; - this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000); - this.request_sender = request_sender; - this.request = request; - - this.logger = request_sender.ua.getLogger('sip.transaction.ict', this.id); - - via = buildViaHeader(request_sender, transport, this.id); - this.request.setHeader('via', via); - - this.request_sender.ua.newTransaction(this); - - // Add the cancel property to the request. - //Will be called from the request instance, not the transaction itself. - this.request.cancel = function (reason, extraHeaders) { - extraHeaders = (extraHeaders || []).slice(); - var length = extraHeaders.length; - var extraHeadersString = null; - for (var idx = 0; idx < length; idx++) { - extraHeadersString = (extraHeadersString || '') + extraHeaders[idx].trim() + '\r\n'; - } - - tr.cancel_request(tr, reason, extraHeadersString); - }; - }; - InviteClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - InviteClientTransaction.prototype.stateChanged = function (state) { - this.state = state; - this.emit('stateChanged'); - }; - - InviteClientTransaction.prototype.send = function () { - var tr = this; - this.stateChanged(C.STATUS_CALLING); - this.B = SIP.Timers.setTimeout(tr.timer_B.bind(tr), SIP.Timers.TIMER_B); - - if (!this.transport.send(this.request)) { - this.onTransportError(); - } - }; - - InviteClientTransaction.prototype.onTransportError = function () { - this.logger.log('transport error occurred, deleting INVITE client transaction ' + this.id); - SIP.Timers.clearTimeout(this.B); - SIP.Timers.clearTimeout(this.D); - SIP.Timers.clearTimeout(this.M); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - - if (this.state !== C.STATUS_ACCEPTED) { - this.request_sender.onTransportError(); - } - }; - - // RFC 6026 7.2 - InviteClientTransaction.prototype.timer_M = function () { - this.logger.debug('Timer M expired for INVITE client transaction ' + this.id); - - if (this.state === C.STATUS_ACCEPTED) { - SIP.Timers.clearTimeout(this.B); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - } - }; - - // RFC 3261 17.1.1 - InviteClientTransaction.prototype.timer_B = function () { - this.logger.debug('Timer B expired for INVITE client transaction ' + this.id); - if (this.state === C.STATUS_CALLING) { - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - this.request_sender.onRequestTimeout(); - } - }; - - InviteClientTransaction.prototype.timer_D = function () { - this.logger.debug('Timer D expired for INVITE client transaction ' + this.id); - SIP.Timers.clearTimeout(this.B); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - }; - - InviteClientTransaction.prototype.sendACK = function (options) { - // TODO: Move PRACK stuff into the transaction layer. That is really where it should be - - var self = this, - ruri; - options = options || {}; - - if (this.response.getHeader('contact')) { - ruri = this.response.parseHeader('contact').uri; - } else { - ruri = this.request.ruri; - } - var ack = new SIP.OutgoingRequest("ACK", ruri, this.request.ua, { - cseq: this.response.cseq, - call_id: this.response.call_id, - from_uri: this.response.from.uri, - from_tag: this.response.from_tag, - to_uri: this.response.to.uri, - to_tag: this.response.to_tag, - route_set: this.response.getHeaders('record-route').reverse() - }, options.extraHeaders || [], options.body); - - this.ackSender = new SIP.RequestSender({ - request: ack, - onRequestTimeout: this.request_sender.applicant.applicant ? this.request_sender.applicant.applicant.onRequestTimeout : function () { - self.logger.warn("ACK Request timed out"); - }, - onTransportError: this.request_sender.applicant.applicant ? this.request_sender.applicant.applicant.onRequestTransportError : function () { - self.loigger.warn("ACK Request had a transport error"); - }, - receiveResponse: options.receiveResponse || function () { - self.logger.warn("Received a response to an ACK which was unexpected. Dropping Response."); - } - }, this.request.ua).send(); - - return ack; - }; - - InviteClientTransaction.prototype.cancel_request = function (tr, reason, extraHeaders) { - var request = tr.request; - - this.cancel = SIP.C.CANCEL + ' ' + request.ruri + ' SIP/2.0\r\n'; - this.cancel += 'Via: ' + request.headers['Via'].toString() + '\r\n'; - - if (this.request.headers['Route']) { - this.cancel += 'Route: ' + request.headers['Route'].toString() + '\r\n'; - } - - this.cancel += 'To: ' + request.headers['To'].toString() + '\r\n'; - this.cancel += 'From: ' + request.headers['From'].toString() + '\r\n'; - this.cancel += 'Call-ID: ' + request.headers['Call-ID'].toString() + '\r\n'; - this.cancel += 'CSeq: ' + request.headers['CSeq'].toString().split(' ')[0] + ' CANCEL\r\n'; - - if (reason) { - this.cancel += 'Reason: ' + reason + '\r\n'; - } - - if (extraHeaders) { - this.cancel += extraHeaders; - } - - this.cancel += 'Content-Length: 0\r\n\r\n'; - - // Send only if a provisional response (>100) has been received. - if (this.state === C.STATUS_PROCEEDING) { - this.transport.send(this.cancel); - } - }; - - InviteClientTransaction.prototype.receiveResponse = function (response) { - var tr = this, - status_code = response.status_code; - - // This may create a circular dependency... - response.transaction = this; - - if (this.response && this.response.status_code === response.status_code && this.response.cseq === response.cseq) { - this.logger.debug("ICT Received a retransmission for cseq: " + response.cseq); - if (this.ackSender) { - this.ackSender.send(); - } - return; - } - this.response = response; - - if (status_code >= 100 && status_code <= 199) { - switch (this.state) { - case C.STATUS_CALLING: - this.stateChanged(C.STATUS_PROCEEDING); - this.request_sender.receiveResponse(response); - if (this.cancel) { - this.transport.send(this.cancel); - } - break; - case C.STATUS_PROCEEDING: - this.request_sender.receiveResponse(response); - break; - } - } else if (status_code >= 200 && status_code <= 299) { - switch (this.state) { - case C.STATUS_CALLING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_ACCEPTED); - this.M = SIP.Timers.setTimeout(tr.timer_M.bind(tr), SIP.Timers.TIMER_M); - this.request_sender.receiveResponse(response); - break; - case C.STATUS_ACCEPTED: - this.request_sender.receiveResponse(response); - break; - } - } else if (status_code >= 300 && status_code <= 699) { - switch (this.state) { - case C.STATUS_CALLING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_COMPLETED); - this.sendACK(); - this.request_sender.receiveResponse(response); - break; - case C.STATUS_COMPLETED: - this.sendACK(); - break; - } - } - }; - - /** - * @augments SIP.Transactions - * @class ACK Client Transaction - * @param {SIP.RequestSender} request_sender - * @param {SIP.OutgoingRequest} request - * @param {SIP.Transport} transport - */ - var AckClientTransaction = function AckClientTransaction(request_sender, request, transport) { - var via; - - this.transport = transport; - this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000); - this.request_sender = request_sender; - this.request = request; - - this.logger = request_sender.ua.getLogger('sip.transaction.nict', this.id); - - via = buildViaHeader(request_sender, transport, this.id); - this.request.setHeader('via', via); - }; - AckClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - AckClientTransaction.prototype.send = function () { - if (!this.transport.send(this.request)) { - this.onTransportError(); - } - }; - - AckClientTransaction.prototype.onTransportError = function () { - this.logger.log('transport error occurred, for an ACK client transaction ' + this.id); - this.request_sender.onTransportError(); - }; - - /** - * @augments SIP.Transactions - * @class Non Invite Server Transaction - * @param {SIP.IncomingRequest} request - * @param {SIP.UA} ua - */ - var NonInviteServerTransaction = function NonInviteServerTransaction(request, ua) { - this.type = C.NON_INVITE_SERVER; - this.id = request.via_branch; - this.request = request; - this.transport = request.transport; - this.ua = ua; - this.last_response = ''; - request.server_transaction = this; - - this.logger = ua.getLogger('sip.transaction.nist', this.id); - - this.state = C.STATUS_TRYING; - - ua.newTransaction(this); - }; - NonInviteServerTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - NonInviteServerTransaction.prototype.stateChanged = function (state) { - this.state = state; - this.emit('stateChanged'); - }; - - NonInviteServerTransaction.prototype.timer_J = function () { - this.logger.debug('Timer J expired for non-INVITE server transaction ' + this.id); - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - }; - - NonInviteServerTransaction.prototype.onTransportError = function () { - if (!this.transportError) { - this.transportError = true; - - this.logger.log('transport error occurred, deleting non-INVITE server transaction ' + this.id); - - SIP.Timers.clearTimeout(this.J); - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - } - }; - - NonInviteServerTransaction.prototype.receiveResponse = function (status_code, response) { - var tr = this; - var deferred = SIP.Utils.defer(); - - if (status_code === 100) { - /* RFC 4320 4.1 - * 'A SIP element MUST NOT - * send any provisional response with a - * Status-Code other than 100 to a non-INVITE request.' - */ - switch (this.state) { - case C.STATUS_TRYING: - this.stateChanged(C.STATUS_PROCEEDING); - if (!this.transport.send(response)) { - this.onTransportError(); - } - break; - case C.STATUS_PROCEEDING: - this.last_response = response; - if (!this.transport.send(response)) { - this.onTransportError(); - deferred.reject(); - } else { - deferred.resolve(); - } - break; - } - } else if (status_code >= 200 && status_code <= 699) { - switch (this.state) { - case C.STATUS_TRYING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_COMPLETED); - this.last_response = response; - this.J = SIP.Timers.setTimeout(tr.timer_J.bind(tr), SIP.Timers.TIMER_J); - if (!this.transport.send(response)) { - this.onTransportError(); - deferred.reject(); - } else { - deferred.resolve(); - } - break; - case C.STATUS_COMPLETED: - break; - } - } - - return deferred.promise; - }; - - /** - * @augments SIP.Transactions - * @class Invite Server Transaction - * @param {SIP.IncomingRequest} request - * @param {SIP.UA} ua - */ - var InviteServerTransaction = function InviteServerTransaction(request, ua) { - this.type = C.INVITE_SERVER; - this.id = request.via_branch; - this.request = request; - this.transport = request.transport; - this.ua = ua; - this.last_response = ''; - request.server_transaction = this; - - this.logger = ua.getLogger('sip.transaction.ist', this.id); - - this.state = C.STATUS_PROCEEDING; - - ua.newTransaction(this); - - this.resendProvisionalTimer = null; - - request.reply(100); - }; - InviteServerTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - InviteServerTransaction.prototype.stateChanged = function (state) { - this.state = state; - this.emit('stateChanged'); - }; - - InviteServerTransaction.prototype.timer_H = function () { - this.logger.debug('Timer H expired for INVITE server transaction ' + this.id); - - if (this.state === C.STATUS_COMPLETED) { - this.logger.warn('transactions', 'ACK for INVITE server transaction was never received, call will be terminated'); - } - - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - }; - - InviteServerTransaction.prototype.timer_I = function () { - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - }; - - // RFC 6026 7.1 - InviteServerTransaction.prototype.timer_L = function () { - this.logger.debug('Timer L expired for INVITE server transaction ' + this.id); - - if (this.state === C.STATUS_ACCEPTED) { - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - } - }; - - InviteServerTransaction.prototype.onTransportError = function () { - if (!this.transportError) { - this.transportError = true; - - this.logger.log('transport error occurred, deleting INVITE server transaction ' + this.id); - - if (this.resendProvisionalTimer !== null) { - SIP.Timers.clearInterval(this.resendProvisionalTimer); - this.resendProvisionalTimer = null; - } - - SIP.Timers.clearTimeout(this.L); - SIP.Timers.clearTimeout(this.H); - SIP.Timers.clearTimeout(this.I); - - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - } - }; - - InviteServerTransaction.prototype.resend_provisional = function () { - if (!this.transport.send(this.last_response)) { - this.onTransportError(); - } - }; - - // INVITE Server Transaction RFC 3261 17.2.1 - InviteServerTransaction.prototype.receiveResponse = function (status_code, response) { - var tr = this; - var deferred = SIP.Utils.defer(); - - if (status_code >= 100 && status_code <= 199) { - switch (this.state) { - case C.STATUS_PROCEEDING: - if (!this.transport.send(response)) { - this.onTransportError(); - } - this.last_response = response; - break; - } - } - - if (status_code > 100 && status_code <= 199 && this.state === C.STATUS_PROCEEDING) { - // Trigger the resendProvisionalTimer only for the first non 100 provisional response. - if (this.resendProvisionalTimer === null) { - this.resendProvisionalTimer = SIP.Timers.setInterval(tr.resend_provisional.bind(tr), SIP.Timers.PROVISIONAL_RESPONSE_INTERVAL); - } - } else if (status_code >= 200 && status_code <= 299) { - switch (this.state) { - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_ACCEPTED); - this.last_response = response; - this.L = SIP.Timers.setTimeout(tr.timer_L.bind(tr), SIP.Timers.TIMER_L); - - if (this.resendProvisionalTimer !== null) { - SIP.Timers.clearInterval(this.resendProvisionalTimer); - this.resendProvisionalTimer = null; - } - /* falls through */ - case C.STATUS_ACCEPTED: - // Note that this point will be reached for proceeding tr.state also. - if (!this.transport.send(response)) { - this.onTransportError(); - deferred.reject(); - } else { - deferred.resolve(); - } - break; - } - } else if (status_code >= 300 && status_code <= 699) { - switch (this.state) { - case C.STATUS_PROCEEDING: - if (this.resendProvisionalTimer !== null) { - SIP.Timers.clearInterval(this.resendProvisionalTimer); - this.resendProvisionalTimer = null; - } - - if (!this.transport.send(response)) { - this.onTransportError(); - deferred.reject(); - } else { - this.stateChanged(C.STATUS_COMPLETED); - this.H = SIP.Timers.setTimeout(tr.timer_H.bind(tr), SIP.Timers.TIMER_H); - deferred.resolve(); - } - break; - } - } - - return deferred.promise; - }; - - /** - * @function - * @param {SIP.UA} ua - * @param {SIP.IncomingRequest} request - * - * @return {boolean} - * INVITE: - * _true_ if retransmission - * _false_ new request - * - * ACK: - * _true_ ACK to non2xx response - * _false_ ACK must be passed to TU (accepted state) - * ACK to 2xx response - * - * CANCEL: - * _true_ no matching invite transaction - * _false_ matching invite transaction and no final response sent - * - * OTHER: - * _true_ retransmission - * _false_ new request - */ - var checkTransaction = function checkTransaction(ua, request) { - var tr; - - switch (request.method) { - case SIP.C.INVITE: - tr = ua.transactions.ist[request.via_branch]; - if (tr) { - switch (tr.state) { - case C.STATUS_PROCEEDING: - tr.transport.send(tr.last_response); - break; - - // RFC 6026 7.1 Invite retransmission - //received while in C.STATUS_ACCEPTED state. Absorb it. - case C.STATUS_ACCEPTED: - break; - } - return true; - } - break; - case SIP.C.ACK: - tr = ua.transactions.ist[request.via_branch]; - - // RFC 6026 7.1 - if (tr) { - if (tr.state === C.STATUS_ACCEPTED) { - return false; - } else if (tr.state === C.STATUS_COMPLETED) { - tr.stateChanged(C.STATUS_CONFIRMED); - tr.I = SIP.Timers.setTimeout(tr.timer_I.bind(tr), SIP.Timers.TIMER_I); - return true; - } - } - - // ACK to 2XX Response. - else { - return false; - } - break; - case SIP.C.CANCEL: - tr = ua.transactions.ist[request.via_branch]; - if (tr) { - request.reply_sl(200); - if (tr.state === C.STATUS_PROCEEDING) { - return false; - } else { - return true; - } - } else { - request.reply_sl(481); - return true; - } - default: - - // Non-INVITE Server Transaction RFC 3261 17.2.2 - tr = ua.transactions.nist[request.via_branch]; - if (tr) { - switch (tr.state) { - case C.STATUS_TRYING: - break; - case C.STATUS_PROCEEDING: - case C.STATUS_COMPLETED: - tr.transport.send(tr.last_response); - break; - } - return true; - } - break; - } - }; - - SIP.Transactions = { - C: C, - checkTransaction: checkTransaction, - NonInviteClientTransaction: NonInviteClientTransaction, - InviteClientTransaction: InviteClientTransaction, - AckClientTransaction: AckClientTransaction, - NonInviteServerTransaction: NonInviteServerTransaction, - InviteServerTransaction: InviteServerTransaction - }; -}; - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Dialog - */ - -/** - * @augments SIP - * @class Class creating a SIP dialog. - * @param {SIP.RTCSession} owner - * @param {SIP.IncomingRequest|SIP.IncomingResponse} message - * @param {Enum} type UAC / UAS - * @param {Enum} state SIP.Dialog.C.STATUS_EARLY / SIP.Dialog.C.STATUS_CONFIRMED - */ - -module.exports = function (SIP) { - - var RequestSender = __webpack_require__(17)(SIP); - - var Dialog, - C = { - // Dialog states - STATUS_EARLY: 1, - STATUS_CONFIRMED: 2 - }; - - // RFC 3261 12.1 - Dialog = function Dialog(owner, message, type, state) { - var contact; - - this.uac_pending_reply = false; - this.uas_pending_reply = false; - - if (!message.hasHeader('contact')) { - return { - error: 'unable to create a Dialog without Contact header field' - }; - } - - if (message instanceof SIP.IncomingResponse) { - state = message.status_code < 200 ? C.STATUS_EARLY : C.STATUS_CONFIRMED; - } else { - // Create confirmed dialog if state is not defined - state = state || C.STATUS_CONFIRMED; - } - - contact = message.parseHeader('contact'); - - // RFC 3261 12.1.1 - if (type === 'UAS') { - this.id = { - call_id: message.call_id, - local_tag: message.to_tag, - remote_tag: message.from_tag, - toString: function toString() { - return this.call_id + this.local_tag + this.remote_tag; - } - }; - this.state = state; - this.remote_seqnum = message.cseq; - this.local_uri = message.parseHeader('to').uri; - this.remote_uri = message.parseHeader('from').uri; - this.remote_target = contact.uri; - this.route_set = message.getHeaders('record-route'); - this.invite_seqnum = message.cseq; - this.local_seqnum = message.cseq; - } - // RFC 3261 12.1.2 - else if (type === 'UAC') { - this.id = { - call_id: message.call_id, - local_tag: message.from_tag, - remote_tag: message.to_tag, - toString: function toString() { - return this.call_id + this.local_tag + this.remote_tag; - } - }; - this.state = state; - this.invite_seqnum = message.cseq; - this.local_seqnum = message.cseq; - this.local_uri = message.parseHeader('from').uri; - this.pracked = []; - this.remote_uri = message.parseHeader('to').uri; - this.remote_target = contact.uri; - this.route_set = message.getHeaders('record-route').reverse(); - } - - this.logger = owner.ua.getLogger('sip.dialog', this.id.toString()); - this.owner = owner; - owner.ua.dialogs[this.id.toString()] = this; - this.logger.log('new ' + type + ' dialog created with status ' + (this.state === C.STATUS_EARLY ? 'EARLY' : 'CONFIRMED')); - owner.emit('dialog', this); - }; - - Dialog.prototype = { - /** - * @param {SIP.IncomingMessage} message - * @param {Enum} UAC/UAS - */ - update: function update(message, type) { - this.state = C.STATUS_CONFIRMED; - - this.logger.log('dialog ' + this.id.toString() + ' changed to CONFIRMED state'); - - if (type === 'UAC') { - // RFC 3261 13.2.2.4 - this.route_set = message.getHeaders('record-route').reverse(); - } - }, - - terminate: function terminate() { - this.logger.log('dialog ' + this.id.toString() + ' deleted'); - if (this.sessionDescriptionHandler && this.state !== C.STATUS_CONFIRMED) { - // TODO: This should call .close() on the handler when implemented - this.sessionDescriptionHandler.close(); - } - delete this.owner.ua.dialogs[this.id.toString()]; - }, - - /** - * @param {String} method request method - * @param {Object} extraHeaders extra headers - * @returns {SIP.OutgoingRequest} - */ - - // RFC 3261 12.2.1.1 - createRequest: function createRequest(method, extraHeaders, body) { - var cseq, request; - extraHeaders = (extraHeaders || []).slice(); - - if (!this.local_seqnum) { - this.local_seqnum = Math.floor(Math.random() * 10000); - } - - cseq = method === SIP.C.CANCEL || method === SIP.C.ACK ? this.invite_seqnum : this.local_seqnum += 1; - - request = new SIP.OutgoingRequest(method, this.remote_target, this.owner.ua, { - 'cseq': cseq, - 'call_id': this.id.call_id, - 'from_uri': this.local_uri, - 'from_tag': this.id.local_tag, - 'to_uri': this.remote_uri, - 'to_tag': this.id.remote_tag, - 'route_set': this.route_set - }, extraHeaders, body); - - request.dialog = this; - - return request; - }, - - /** - * @param {SIP.IncomingRequest} request - * @returns {Boolean} - */ - - // RFC 3261 12.2.2 - checkInDialogRequest: function checkInDialogRequest(request) { - var self = this; - - if (!this.remote_seqnum) { - this.remote_seqnum = request.cseq; - } else if (request.cseq < this.remote_seqnum) { - //Do not try to reply to an ACK request. - if (request.method !== SIP.C.ACK) { - request.reply(500); - } - if (request.cseq === this.invite_seqnum) { - return true; - } - return false; - } - - switch (request.method) { - // RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR- - case SIP.C.INVITE: - if (this.uac_pending_reply === true) { - request.reply(491); - } else if (this.uas_pending_reply === true && request.cseq > this.remote_seqnum) { - var retryAfter = (Math.random() * 10 | 0) + 1; - request.reply(500, null, ['Retry-After:' + retryAfter]); - this.remote_seqnum = request.cseq; - return false; - } else { - this.uas_pending_reply = true; - request.server_transaction.on('stateChanged', function stateChanged() { - if (this.state === SIP.Transactions.C.STATUS_ACCEPTED || this.state === SIP.Transactions.C.STATUS_COMPLETED || this.state === SIP.Transactions.C.STATUS_TERMINATED) { - - this.removeListener('stateChanged', stateChanged); - self.uas_pending_reply = false; - } - }); - } - - // RFC3261 12.2.2 Replace the dialog`s remote target URI if the request is accepted - if (request.hasHeader('contact')) { - request.server_transaction.on('stateChanged', function () { - if (this.state === SIP.Transactions.C.STATUS_ACCEPTED) { - self.remote_target = request.parseHeader('contact').uri; - } - }); - } - break; - case SIP.C.NOTIFY: - // RFC6665 3.2 Replace the dialog`s remote target URI if the request is accepted - if (request.hasHeader('contact')) { - request.server_transaction.on('stateChanged', function () { - if (this.state === SIP.Transactions.C.STATUS_COMPLETED) { - self.remote_target = request.parseHeader('contact').uri; - } - }); - } - break; - } - - if (request.cseq > this.remote_seqnum) { - this.remote_seqnum = request.cseq; - } - - return true; - }, - - sendRequest: function sendRequest(applicant, method, options) { - options = options || {}; - - var extraHeaders = (options.extraHeaders || []).slice(); - - var body = null; - if (options.body) { - if (options.body.body) { - body = options.body; - } else { - body = {}; - body.body = options.body; - if (options.contentType) { - body.contentType = options.contentType; - } - } - } - - var request = this.createRequest(method, extraHeaders, body), - request_sender = new RequestSender(this, applicant, request); - - request_sender.send(); - - return request; - }, - - /** - * @param {SIP.IncomingRequest} request - */ - receiveRequest: function receiveRequest(request) { - //Check in-dialog request - if (!this.checkInDialogRequest(request)) { - return; - } - - this.owner.receiveRequest(request); - } - }; - - Dialog.C = C; - SIP.Dialog = Dialog; -}; - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * @fileoverview In-Dialog Request Sender - */ - -/** - * @augments SIP.Dialog - * @class Class creating an In-dialog request sender. - * @param {SIP.Dialog} dialog - * @param {Object} applicant - * @param {SIP.OutgoingRequest} request - */ -/** - * @fileoverview in-Dialog Request Sender - */ - -module.exports = function (SIP) { - var RequestSender; - - RequestSender = function RequestSender(dialog, applicant, request) { - - this.dialog = dialog; - this.applicant = applicant; - this.request = request; - - // RFC3261 14.1 Modifying an Existing Session. UAC Behavior. - this.reattempt = false; - this.reattemptTimer = null; - }; - - RequestSender.prototype = { - send: function send() { - var self = this, - request_sender = new SIP.RequestSender(this, this.dialog.owner.ua); - - request_sender.send(); - - // RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR- - if (this.request.method === SIP.C.INVITE && request_sender.clientTransaction.state !== SIP.Transactions.C.STATUS_TERMINATED) { - this.dialog.uac_pending_reply = true; - request_sender.clientTransaction.on('stateChanged', function stateChanged() { - if (this.state === SIP.Transactions.C.STATUS_ACCEPTED || this.state === SIP.Transactions.C.STATUS_COMPLETED || this.state === SIP.Transactions.C.STATUS_TERMINATED) { - - this.removeListener('stateChanged', stateChanged); - self.dialog.uac_pending_reply = false; - } - }); - } - }, - - onRequestTimeout: function onRequestTimeout() { - this.applicant.onRequestTimeout(); - }, - - onTransportError: function onTransportError() { - this.applicant.onTransportError(); - }, - - receiveResponse: function receiveResponse(response) { - var self = this; - - // RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog. - if (response.status_code === 408 || response.status_code === 481) { - this.applicant.onDialogError(response); - } else if (response.method === SIP.C.INVITE && response.status_code === 491) { - if (this.reattempt) { - this.applicant.receiveResponse(response); - } else { - this.request.cseq.value = this.dialog.local_seqnum += 1; - this.reattemptTimer = SIP.Timers.setTimeout(function () { - if (self.applicant.owner.status !== SIP.Session.C.STATUS_TERMINATED) { - self.reattempt = true; - self.request_sender.send(); - } - }, this.getReattemptTimeout()); - } - } else { - this.applicant.receiveResponse(response); - } - } - }; - - return RequestSender; -}; - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * @fileoverview Request Sender - */ - -/** - * @augments SIP - * @class Class creating a request sender. - * @param {Object} applicant - * @param {SIP.UA} ua - */ - -module.exports = function (SIP) { - var RequestSender; - - RequestSender = function RequestSender(applicant, ua) { - this.logger = ua.getLogger('sip.requestsender'); - this.ua = ua; - this.applicant = applicant; - this.method = applicant.request.method; - this.request = applicant.request; - this.credentials = null; - this.challenged = false; - this.staled = false; - - // If ua is in closing process or even closed just allow sending Bye and ACK - if (ua.status === SIP.UA.C.STATUS_USER_CLOSED && (this.method !== SIP.C.BYE || this.method !== SIP.C.ACK)) { - this.onTransportError(); - } - }; - - /** - * Create the client transaction and send the message. - */ - RequestSender.prototype = { - send: function send() { - switch (this.method) { - case "INVITE": - this.clientTransaction = new SIP.Transactions.InviteClientTransaction(this, this.request, this.ua.transport); - break; - case "ACK": - this.clientTransaction = new SIP.Transactions.AckClientTransaction(this, this.request, this.ua.transport); - break; - default: - this.clientTransaction = new SIP.Transactions.NonInviteClientTransaction(this, this.request, this.ua.transport); - } - this.clientTransaction.send(); - - return this.clientTransaction; - }, - - /** - * Callback fired when receiving a request timeout error from the client transaction. - * To be re-defined by the applicant. - * @event - */ - onRequestTimeout: function onRequestTimeout() { - this.applicant.onRequestTimeout(); - }, - - /** - * Callback fired when receiving a transport error from the client transaction. - * To be re-defined by the applicant. - * @event - */ - onTransportError: function onTransportError() { - this.applicant.onTransportError(); - }, - - /** - * Called from client transaction when receiving a correct response to the request. - * Authenticate request if needed or pass the response back to the applicant. - * @param {SIP.IncomingResponse} response - */ - receiveResponse: function receiveResponse(response) { - var cseq, - challenge, - authorization_header_name, - status_code = response.status_code; - - /* - * Authentication - * Authenticate once. _challenged_ flag used to avoid infinite authentications. - */ - if (status_code === 401 || status_code === 407) { - - // Get and parse the appropriate WWW-Authenticate or Proxy-Authenticate header. - if (response.status_code === 401) { - challenge = response.parseHeader('www-authenticate'); - authorization_header_name = 'authorization'; - } else { - challenge = response.parseHeader('proxy-authenticate'); - authorization_header_name = 'proxy-authorization'; - } - - // Verify it seems a valid challenge. - if (!challenge) { - this.logger.warn(response.status_code + ' with wrong or missing challenge, cannot authenticate'); - this.applicant.receiveResponse(response); - return; - } - - if (!this.challenged || !this.staled && challenge.stale === true) { - if (!this.credentials) { - this.credentials = this.ua.configuration.authenticationFactory(this.ua); - } - - // Verify that the challenge is really valid. - if (!this.credentials.authenticate(this.request, challenge)) { - this.applicant.receiveResponse(response); - return; - } - this.challenged = true; - - if (challenge.stale) { - this.staled = true; - } - - if (response.method === SIP.C.REGISTER) { - cseq = this.applicant.cseq += 1; - } else if (this.request.dialog) { - cseq = this.request.dialog.local_seqnum += 1; - } else { - cseq = this.request.cseq + 1; - this.request.cseq = cseq; - } - this.request.setHeader('cseq', cseq + ' ' + this.method); - - this.request.setHeader(authorization_header_name, this.credentials.toString()); - this.send(); - } else { - this.applicant.receiveResponse(response); - } - } else { - this.applicant.receiveResponse(response); - } - } - }; - - SIP.RequestSender = RequestSender; -}; - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function (SIP) { - - var RegisterContext; - - RegisterContext = function RegisterContext(ua) { - var params = {}, - regId = 1; - - this.registrar = ua.configuration.registrarServer; - this.expires = ua.configuration.registerExpires; - - // Contact header - this.contact = ua.contact.toString(); - - if (regId) { - this.contact += ';reg-id=' + regId; - this.contact += ';+sip.instance=""'; - } - - // Call-ID and CSeq values RFC3261 10.2 - this.call_id = SIP.Utils.createRandomToken(22); - this.cseq = Math.floor(Math.random() * 10000); - - this.to_uri = ua.configuration.uri; - - params.to_uri = this.to_uri; - params.to_displayName = ua.configuration.displayName; - params.call_id = this.call_id; - params.cseq = this.cseq; - - // Extends ClientContext - SIP.Utils.augment(this, SIP.ClientContext, [ua, 'REGISTER', this.registrar, { params: params }]); - - this.registrationTimer = null; - this.registrationExpiredTimer = null; - - // Set status - this.registered = false; - - this.logger = ua.getLogger('sip.registercontext'); - }; - - RegisterContext.prototype = { - register: function register(options) { - var self = this, - extraHeaders; - - // Handle Options - this.options = options || {}; - extraHeaders = (this.options.extraHeaders || []).slice(); - extraHeaders.push('Contact: ' + this.contact + ';expires=' + this.expires); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - // Save original extraHeaders to be used in .close - this.closeHeaders = this.options.closeWithHeaders ? (this.options.extraHeaders || []).slice() : []; - - this.receiveResponse = function (response) { - var contact, - expires, - contacts = response.getHeaders('contact').length, - cause; - - // Discard responses to older REGISTER/un-REGISTER requests. - if (response.cseq !== this.cseq) { - return; - } - - // Clear registration timer - if (this.registrationTimer !== null) { - SIP.Timers.clearTimeout(this.registrationTimer); - this.registrationTimer = null; - } - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - this.emit('progress', response); - break; - case /^2[0-9]{2}$/.test(response.status_code): - this.emit('accepted', response); - - if (response.hasHeader('expires')) { - expires = response.getHeader('expires'); - } - - if (this.registrationExpiredTimer !== null) { - SIP.Timers.clearTimeout(this.registrationExpiredTimer); - this.registrationExpiredTimer = null; - } - - // Search the Contact pointing to us and update the expires value accordingly. - if (!contacts) { - this.logger.warn('no Contact header in response to REGISTER, response ignored'); - break; - } - - while (contacts--) { - contact = response.parseHeader('contact', contacts); - if (contact.uri.user === this.ua.contact.uri.user) { - expires = contact.getParam('expires'); - break; - } else { - contact = null; - } - } - - if (!contact) { - this.logger.warn('no Contact header pointing to us, response ignored'); - break; - } - - if (!expires) { - expires = this.expires; - } - - // Re-Register before the expiration interval has elapsed. - // For that, decrease the expires value. ie: 3 seconds - this.registrationTimer = SIP.Timers.setTimeout(function () { - self.registrationTimer = null; - self.register(self.options); - }, expires * 1000 - 3000); - this.registrationExpiredTimer = SIP.Timers.setTimeout(function () { - self.logger.warn('registration expired'); - if (self.registered) { - self.unregistered(null, SIP.C.causes.EXPIRES); - } - }, expires * 1000); - - //Save gruu values - if (contact.hasParam('temp-gruu')) { - this.ua.contact.temp_gruu = SIP.URI.parse(contact.getParam('temp-gruu').replace(/"/g, '')); - } - if (contact.hasParam('pub-gruu')) { - this.ua.contact.pub_gruu = SIP.URI.parse(contact.getParam('pub-gruu').replace(/"/g, '')); - } - - this.registered = true; - this.emit('registered', response || null); - break; - // Interval too brief RFC3261 10.2.8 - case /^423$/.test(response.status_code): - if (response.hasHeader('min-expires')) { - // Increase our registration interval to the suggested minimum - this.expires = response.getHeader('min-expires'); - // Attempt the registration again immediately - this.register(this.options); - } else { - //This response MUST contain a Min-Expires header field - this.logger.warn('423 response received for REGISTER without Min-Expires'); - this.registrationFailure(response, SIP.C.causes.SIP_FAILURE_CODE); - } - break; - default: - cause = SIP.Utils.sipErrorCause(response.status_code); - this.registrationFailure(response, cause); - } - }; - - this.onRequestTimeout = function () { - this.registrationFailure(null, SIP.C.causes.REQUEST_TIMEOUT); - }; - - this.onTransportError = function () { - this.registrationFailure(null, SIP.C.causes.CONNECTION_ERROR); - }; - - this.cseq++; - this.request.cseq = this.cseq; - this.request.setHeader('cseq', this.cseq + ' REGISTER'); - this.request.extraHeaders = extraHeaders; - this.send(); - }, - - registrationFailure: function registrationFailure(response, cause) { - this.emit('failed', response || null, cause || null); - }, - - onTransportClosed: function onTransportClosed() { - this.registered_before = this.registered; - if (this.registrationTimer !== null) { - SIP.Timers.clearTimeout(this.registrationTimer); - this.registrationTimer = null; - } - - if (this.registrationExpiredTimer !== null) { - SIP.Timers.clearTimeout(this.registrationExpiredTimer); - this.registrationExpiredTimer = null; - } - - if (this.registered) { - this.unregistered(null, SIP.C.causes.CONNECTION_ERROR); - } - }, - - onTransportConnected: function onTransportConnected() { - this.register(this.options); - }, - - close: function close() { - var options = { - all: false, - extraHeaders: this.closeHeaders - }; - - this.registered_before = this.registered; - if (this.registered) { - this.unregister(options); - } - }, - - unregister: function unregister(options) { - var extraHeaders; - - options = options || {}; - - if (!this.registered && !options.all) { - this.logger.warn('Already unregistered, but sending an unregister anyways.'); - } - - extraHeaders = (options.extraHeaders || []).slice(); - - this.registered = false; - - // Clear the registration timer. - if (this.registrationTimer !== null) { - SIP.Timers.clearTimeout(this.registrationTimer); - this.registrationTimer = null; - } - - if (options.all) { - extraHeaders.push('Contact: *'); - extraHeaders.push('Expires: 0'); - } else { - extraHeaders.push('Contact: ' + this.contact + ';expires=0'); - } - - this.receiveResponse = function (response) { - var cause; - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - this.emit('progress', response); - break; - case /^2[0-9]{2}$/.test(response.status_code): - this.emit('accepted', response); - if (this.registrationExpiredTimer !== null) { - SIP.Timers.clearTimeout(this.registrationExpiredTimer); - this.registrationExpiredTimer = null; - } - this.unregistered(response); - break; - default: - cause = SIP.Utils.sipErrorCause(response.status_code); - this.unregistered(response, cause); - } - }; - - this.onRequestTimeout = function () { - // Not actually unregistered... - //this.unregistered(null, SIP.C.causes.REQUEST_TIMEOUT); - }; - - this.onTransportError = function () { - // Not actually unregistered... - //this.unregistered(null, SIP.C.causes.CONNECTION_ERROR); - }; - - this.cseq++; - this.request.cseq = this.cseq; - this.request.setHeader('cseq', this.cseq + ' REGISTER'); - this.request.extraHeaders = extraHeaders; - - this.send(); - }, - - unregistered: function unregistered(response, cause) { - this.registered = false; - this.emit('unregistered', response || null, cause || null); - } - - }; - - SIP.RegisterContext = RegisterContext; -}; - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* eslint-disable */ -/** - * @fileoverview SessionDescriptionHandler - */ - -/* SessionDescriptionHandler - * @class PeerConnection helper Class. - * @param {SIP.Session} session - * @param {Object} [options] - */ - -module.exports = function (EventEmitter) { - var SessionDescriptionHandler = function SessionDescriptionHandler(session, options) {}; - - SessionDescriptionHandler.prototype = Object.create(EventEmitter.prototype, { - - /** - * Destructor - */ - close: { value: function close() {} }, - - /** - * Gets the local description from the underlying media implementation - * @param {Object} [options] Options object to be used by getDescription - * @param {Array} [modifiers] Array with one time use description modifiers - * @returns {Promise} Promise that resolves with the local description to be used for the session - */ - getDescription: { value: function getDescription(options, modifiers) {} }, - - /** - * Check if the Session Description Handler can handle the Content-Type described by a SIP Message - * @param {String} contentType The content type that is in the SIP Message - * @returns {boolean} - */ - hasDescription: { value: function hasSessionDescription(contentType) {} }, - - /** - * The modifier that should be used when the session would like to place the call on hold - * @param {String} [sdp] The description that will be modified - * @returns {Promise} Promise that resolves with modified SDP - */ - holdModifier: { value: function holdModifier(sdp) {} }, - - /** - * Set the remote description to the underlying media implementation - * @param {String} sessionDescription The description provided by a SIP message to be set on the media implementation - * @param {Object} [options] Options object to be used by setDescription - * @param {Array} [modifiers] Array with one time use description modifiers - * @returns {Promise} Promise that resolves once the description is set - */ - setDescription: { value: function setDescription(sessionDescription, options, modifiers) {} } - }); - - return SessionDescriptionHandler; -}; - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function (SIP) { - var ClientContext; - - ClientContext = function ClientContext(ua, method, target, options) { - var originalTarget = target; - - // Validate arguments - if (target === undefined) { - throw new TypeError('Not enough arguments'); - } - - this.ua = ua; - this.logger = ua.getLogger('sip.clientcontext'); - this.method = method; - target = ua.normalizeTarget(target); - if (!target) { - throw new TypeError('Invalid target: ' + originalTarget); - } - - /* Options - * - extraHeaders - * - params - * - contentType - * - body - */ - options = Object.create(options || Object.prototype); - options.extraHeaders = (options.extraHeaders || []).slice(); - - // Build the request - this.request = new SIP.OutgoingRequest(this.method, target, this.ua, options.params, options.extraHeaders); - if (options.body) { - this.body = {}; - this.body.body = options.body; - if (options.contentType) { - this.body.contentType = options.contentType; - } - this.request.body = this.body; - } - - /* Set other properties from the request */ - this.localIdentity = this.request.from; - this.remoteIdentity = this.request.to; - - this.data = {}; - }; - ClientContext.prototype = Object.create(SIP.EventEmitter.prototype); - - ClientContext.prototype.send = function () { - new SIP.RequestSender(this, this.ua).send(); - return this; - }; - - ClientContext.prototype.cancel = function (options) { - options = options || {}; - - options.extraHeaders = (options.extraHeaders || []).slice(); - - var cancel_reason = SIP.Utils.getCancelReason(options.status_code, options.reason_phrase); - this.request.cancel(cancel_reason, options.extraHeaders); - - this.emit('cancel'); - }; - - ClientContext.prototype.receiveResponse = function (response) { - var cause = SIP.Utils.getReasonPhrase(response.status_code); - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - this.emit('progress', response, cause); - break; - - case /^2[0-9]{2}$/.test(response.status_code): - if (this.ua.applicants[this]) { - delete this.ua.applicants[this]; - } - this.emit('accepted', response, cause); - break; - - default: - if (this.ua.applicants[this]) { - delete this.ua.applicants[this]; - } - this.emit('rejected', response, cause); - this.emit('failed', response, cause); - break; - } - }; - - ClientContext.prototype.onRequestTimeout = function () { - this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT); - }; - - ClientContext.prototype.onTransportError = function () { - this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR); - }; - - SIP.ClientContext = ClientContext; -}; - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function (SIP) { - var ServerContext; - - ServerContext = function ServerContext(ua, request) { - this.ua = ua; - this.logger = ua.getLogger('sip.servercontext'); - this.request = request; - if (request.method === SIP.C.INVITE) { - this.transaction = new SIP.Transactions.InviteServerTransaction(request, ua); - } else { - this.transaction = new SIP.Transactions.NonInviteServerTransaction(request, ua); - } - - if (request.body) { - this.body = request.body; - } - if (request.hasHeader('Content-Type')) { - this.contentType = request.getHeader('Content-Type'); - } - this.method = request.method; - - this.data = {}; - - this.localIdentity = request.to; - this.remoteIdentity = request.from; - }; - - ServerContext.prototype = Object.create(SIP.EventEmitter.prototype); - - ServerContext.prototype.progress = function (options) { - options = Object.create(options || Object.prototype); - options.statusCode || (options.statusCode = 180); - options.minCode = 100; - options.maxCode = 199; - options.events = ['progress']; - return this.reply(options); - }; - - ServerContext.prototype.accept = function (options) { - options = Object.create(options || Object.prototype); - options.statusCode || (options.statusCode = 200); - options.minCode = 200; - options.maxCode = 299; - options.events = ['accepted']; - return this.reply(options); - }; - - ServerContext.prototype.reject = function (options) { - options = Object.create(options || Object.prototype); - options.statusCode || (options.statusCode = 480); - options.minCode = 300; - options.maxCode = 699; - options.events = ['rejected', 'failed']; - return this.reply(options); - }; - - ServerContext.prototype.reply = function (options) { - options = options || {}; // This is okay, so long as we treat options as read-only in this method - var statusCode = options.statusCode || 100, - minCode = options.minCode || 100, - maxCode = options.maxCode || 699, - reasonPhrase = SIP.Utils.getReasonPhrase(statusCode, options.reasonPhrase), - extraHeaders = options.extraHeaders || [], - body = options.body, - events = options.events || [], - response; - - if (statusCode < minCode || statusCode > maxCode) { - throw new TypeError('Invalid statusCode: ' + statusCode); - } - response = this.request.reply(statusCode, reasonPhrase, extraHeaders, body); - events.forEach(function (event) { - this.emit(event, response, reasonPhrase); - }, this); - - return this; - }; - - ServerContext.prototype.onRequestTimeout = function () { - this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT); - }; - - ServerContext.prototype.onTransportError = function () { - this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR); - }; - - SIP.ServerContext = ServerContext; -}; - -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function (SIP) { - - var DTMF = __webpack_require__(24)(SIP); - - var Session, - InviteServerContext, - InviteClientContext, - ReferServerContext, - ReferClientContext, - C = { - //Session states - STATUS_NULL: 0, - STATUS_INVITE_SENT: 1, - STATUS_1XX_RECEIVED: 2, - STATUS_INVITE_RECEIVED: 3, - STATUS_WAITING_FOR_ANSWER: 4, - STATUS_ANSWERED: 5, - STATUS_WAITING_FOR_PRACK: 6, - STATUS_WAITING_FOR_ACK: 7, - STATUS_CANCELED: 8, - STATUS_TERMINATED: 9, - STATUS_ANSWERED_WAITING_FOR_PRACK: 10, - STATUS_EARLY_MEDIA: 11, - STATUS_CONFIRMED: 12 - }; - - /* - * @param {function returning SIP.sessionDescriptionHandler} [sessionDescriptionHandlerFactory] - * (See the documentation for the sessionDescriptionHandlerFactory argument of the UA constructor.) - */ - Session = function Session(sessionDescriptionHandlerFactory) { - this.status = C.STATUS_NULL; - this.dialog = null; - this.pendingReinvite = false; - this.earlyDialogs = {}; - if (!sessionDescriptionHandlerFactory) { - throw new SIP.Exceptions.SessionDescriptionHandlerMissing('A session description handler is required for the session to function'); - } - this.sessionDescriptionHandlerFactory = sessionDescriptionHandlerFactory; - - this.hasOffer = false; - this.hasAnswer = false; - - // Session Timers - this.timers = { - ackTimer: null, - expiresTimer: null, - invite2xxTimer: null, - userNoAnswerTimer: null, - rel1xxTimer: null, - prackTimer: null - }; - - // Session info - this.startTime = null; - this.endTime = null; - this.tones = null; - - // Hold state - this.local_hold = false; - - // Flag to disable renegotiation. When set to true, it will not renegotiate - // and will throw a RENEGOTIATION_ERROR - this.disableRenegotiation = false; - - this.early_sdp = null; - this.rel100 = SIP.C.supported.UNSUPPORTED; - }; - - Session.prototype = { - dtmf: function dtmf(tones, options) { - var tone, - dtmfs = [], - self = this; - - options = options || {}; - - if (tones === undefined) { - throw new TypeError('Not enough arguments'); - } - - // Check Session Status - if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_WAITING_FOR_ACK) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - // Check tones - if (typeof tones !== 'string' && typeof tones !== 'number' || !tones.toString().match(/^[0-9A-D#*,]+$/i)) { - throw new TypeError('Invalid tones: ' + tones); - } - - tones = tones.toString().split(''); - - while (tones.length > 0) { - dtmfs.push(new DTMF(this, tones.shift(), options)); - } - - if (this.tones) { - // Tones are already queued, just add to the queue - this.tones = this.tones.concat(dtmfs); - return this; - } - - var sendDTMF = function sendDTMF() { - var dtmf, timeout; - - if (self.status === C.STATUS_TERMINATED || !self.tones || self.tones.length === 0) { - // Stop sending DTMF - self.tones = null; - return this; - } - - dtmf = self.tones.shift(); - - if (tone === ',') { - timeout = 2000; - } else { - dtmf.on('failed', function () { - self.tones = null; - }); - dtmf.send(options); - timeout = dtmf.duration + dtmf.interToneGap; - } - - // Set timeout for the next tone - SIP.Timers.setTimeout(sendDTMF, timeout); - }; - - this.tones = dtmfs; - sendDTMF(); - return this; - }, - - bye: function bye(options) { - options = Object.create(options || Object.prototype); - var statusCode = options.statusCode; - - // Check Session Status - if (this.status === C.STATUS_TERMINATED) { - this.logger.error('Error: Attempted to send BYE in a terminated session.'); - return this; - } - - this.logger.log('terminating Session'); - - if (statusCode && (statusCode < 200 || statusCode >= 700)) { - throw new TypeError('Invalid statusCode: ' + statusCode); - } - - options.receiveResponse = function () {}; - - return this.sendRequest(SIP.C.BYE, options).terminated(); - }, - - refer: function refer(target, options) { - options = options || {}; - - // Check Session Status - if (this.status !== C.STATUS_CONFIRMED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - this.referContext = new SIP.ReferClientContext(this.ua, this, target, options); - - this.emit('referRequested', this.referContext); - - this.referContext.refer(); - }, - - sendRequest: function sendRequest(method, options) { - options = options || {}; - var self = this; - - var request = new SIP.OutgoingRequest(method, this.dialog.remote_target, this.ua, { - cseq: options.cseq || (this.dialog.local_seqnum += 1), - call_id: this.dialog.id.call_id, - from_uri: this.dialog.local_uri, - from_tag: this.dialog.id.local_tag, - to_uri: this.dialog.remote_uri, - to_tag: this.dialog.id.remote_tag, - route_set: this.dialog.route_set, - statusCode: options.statusCode, - reasonPhrase: options.reasonPhrase - }, options.extraHeaders || [], options.body); - - new SIP.RequestSender({ - request: request, - onRequestTimeout: function onRequestTimeout() { - self.onRequestTimeout(); - }, - onTransportError: function onTransportError() { - self.onTransportError(); - }, - receiveResponse: options.receiveResponse || function (response) { - self.receiveNonInviteResponse(response); - } - }, this.ua).send(); - - // Emit the request event - this.emit(method.toLowerCase(), request); - - return this; - }, - - close: function close() { - var idx; - - if (this.status === C.STATUS_TERMINATED) { - return this; - } - - this.logger.log('closing INVITE session ' + this.id); - - // 1st Step. Terminate media. - if (this.sessionDescriptionHandler) { - this.sessionDescriptionHandler.close(); - } - - // 2nd Step. Terminate signaling. - - // Clear session timers - for (idx in this.timers) { - SIP.Timers.clearTimeout(this.timers[idx]); - } - - // Terminate dialogs - - // Terminate confirmed dialog - if (this.dialog) { - this.dialog.terminate(); - delete this.dialog; - } - - // Terminate early dialogs - for (idx in this.earlyDialogs) { - this.earlyDialogs[idx].terminate(); - delete this.earlyDialogs[idx]; - } - - this.status = C.STATUS_TERMINATED; - - delete this.ua.sessions[this.id]; - return this; - }, - - createDialog: function createDialog(message, type, early) { - var dialog, - early_dialog, - local_tag = message[type === 'UAS' ? 'to_tag' : 'from_tag'], - remote_tag = message[type === 'UAS' ? 'from_tag' : 'to_tag'], - id = message.call_id + local_tag + remote_tag; - - early_dialog = this.earlyDialogs[id]; - - // Early Dialog - if (early) { - if (early_dialog) { - return true; - } else { - early_dialog = new SIP.Dialog(this, message, type, SIP.Dialog.C.STATUS_EARLY); - - // Dialog has been successfully created. - if (early_dialog.error) { - this.logger.error(early_dialog.error); - this.failed(message, SIP.C.causes.INTERNAL_ERROR); - return false; - } else { - this.earlyDialogs[id] = early_dialog; - return true; - } - } - } - // Confirmed Dialog - else { - // In case the dialog is in _early_ state, update it - if (early_dialog) { - early_dialog.update(message, type); - this.dialog = early_dialog; - delete this.earlyDialogs[id]; - for (var dia in this.earlyDialogs) { - this.earlyDialogs[dia].terminate(); - delete this.earlyDialogs[dia]; - } - return true; - } - - // Otherwise, create a _confirmed_ dialog - dialog = new SIP.Dialog(this, message, type); - - if (dialog.error) { - this.logger.error(dialog.error); - this.failed(message, SIP.C.causes.INTERNAL_ERROR); - return false; - } else { - this.to_tag = message.to_tag; - this.dialog = dialog; - return true; - } - } - }, - - /** - * Hold - */ - hold: function hold(options, modifiers) { - - if (this.status !== C.STATUS_WAITING_FOR_ACK && this.status !== C.STATUS_CONFIRMED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - if (this.local_hold) { - this.logger.log('Session is already on hold, cannot put it on hold again'); - return; - } - - options = options || {}; - options.modifiers = modifiers || []; - options.modifiers.push(this.sessionDescriptionHandler.holdModifier); - - this.local_hold = true; - - this.sendReinvite(options); - }, - - /** - * Unhold - */ - unhold: function unhold(options, modifiers) { - - if (this.status !== C.STATUS_WAITING_FOR_ACK && this.status !== C.STATUS_CONFIRMED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - if (!this.local_hold) { - this.logger.log('Session is not on hold, cannot unhold it'); - return; - } - - options = options || {}; - - if (modifiers) { - options.modifiers = modifiers; - } - - this.local_hold = false; - - this.sendReinvite(options); - }, - - reinvite: function reinvite(options, modifiers) { - options = options || {}; - - if (modifiers) { - options.modifiers = modifiers; - } - - return this.sendReinvite(options); - }, - - /** - * In dialog INVITE Reception - * @private - */ - receiveReinvite: function receiveReinvite(request) { - var self = this, - promise; - // TODO: Should probably check state of the session - - self.emit('reinvite', this); - - // Invite w/o SDP - if (request.getHeader('Content-Length') === '0' && !request.getHeader('Content-Type')) { - promise = this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions, this.modifiers); - - // Invite w/ SDP - } else if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) { - promise = this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler, this.sessionDescriptionHandlerOptions, this.modifiers)); - - // Bad Packet (should never get hit) - } else { - request.reply(415); - this.emit('reinviteFailed', self); - return; - } - - var _receiveRequest = this.receiveRequest; - - // HACK to catch the ACK - this.receiveRequest = function (request) { - if (request.method === SIP.C.ACK && this.status === C.STATUS_WAITING_FOR_ACK && this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) { - this.hasAnswer = true; - this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function () { - SIP.Timers.clearTimeout(this.timers.ackTimer); - SIP.Timers.clearTimeout(this.timers.invite2xxTimer); - this.status = C.STATUS_CONFIRMED; - - this.emit('confirmed', request); - }.bind(this)); - } else { - _receiveRequest.call(this, request); - } - }.bind(this); - - promise.catch(function onFailure(e) { - var statusCode; - if (e instanceof SIP.Exceptions.GetDescriptionError) { - statusCode = 500; - } else if (e instanceof SIP.Exceptions.RenegotiationError) { - self.emit('renegotiationError', e); - self.logger.warn(e); - statusCode = 488; - } else { - self.logger.error(e); - statusCode = 488; - } - request.reply(statusCode); - self.emit('reinviteFailed', self); - }).then(function (description) { - var extraHeaders = ['Contact: ' + self.contact]; - request.reply(200, null, extraHeaders, description, function () { - self.status = C.STATUS_WAITING_FOR_ACK; - - self.setACKTimer(); - self.emit('reinviteAccepted', self); - }); - }); - }, - - sendReinvite: function sendReinvite(options) { - if (this.pendingReinvite) { - this.logger.warn('Reinvite in progress. Please wait until complete, then try again.'); - return; - } - this.pendingReinvite = true; - options = options || {}; - options.modifiers = options.modifiers || []; - - var self = this, - extraHeaders = (options.extraHeaders || []).slice(); - - extraHeaders.push('Contact: ' + this.contact); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers).then(function (description) { - self.sendRequest(SIP.C.INVITE, { - extraHeaders: extraHeaders, - body: description, - receiveResponse: self.receiveReinviteResponse.bind(self) - }); - }).catch(function onFailure(e) { - if (e instanceof SIP.Exceptions.RenegotiationError) { - self.pendingReinvite = false; - self.emit('renegotiationError', e); - self.logger.warn('Renegotiation Error'); - self.logger.warn(e); - return; - } - self.logger.error('sessionDescriptionHandler error'); - self.logger.error(e); - }); - }, - - receiveRequest: function receiveRequest(request) { - switch (request.method) { - case SIP.C.BYE: - request.reply(200); - if (this.status === C.STATUS_CONFIRMED) { - this.emit('bye', request); - this.terminated(request, SIP.C.causes.BYE); - } - break; - case SIP.C.INVITE: - if (this.status === C.STATUS_CONFIRMED) { - this.logger.log('re-INVITE received'); - this.receiveReinvite(request); - } - break; - case SIP.C.INFO: - if (this.status === C.STATUS_CONFIRMED || this.status === C.STATUS_WAITING_FOR_ACK) { - if (this.onInfo) { - return this.onInfo(request); - } - - var body, - tone, - duration, - contentType = request.getHeader('content-type'), - reg_tone = /^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/, - reg_duration = /^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/; - - if (contentType) { - if (contentType.match(/^application\/dtmf-relay/i)) { - if (request.body) { - body = request.body.split('\r\n', 2); - if (body.length === 2) { - if (reg_tone.test(body[0])) { - tone = body[0].replace(reg_tone, "$2"); - } - if (reg_duration.test(body[1])) { - duration = parseInt(body[1].replace(reg_duration, "$2"), 10); - } - } - } - - new DTMF(this, tone, { duration: duration }).init_incoming(request); - } else { - request.reply(415, null, ["Accept: application/dtmf-relay"]); - } - } - } - break; - case SIP.C.REFER: - if (this.status === C.STATUS_CONFIRMED) { - this.logger.log('REFER received'); - this.referContext = new SIP.ReferServerContext(this.ua, request); - var hasReferListener = this.listeners('referRequested').length; - if (hasReferListener) { - this.emit('referRequested', this.referContext); - } else { - this.logger.log('No referRequested listeners, automatically accepting and following the refer'); - var options = { followRefer: true }; - if (this.passedOptions) { - options.inviteOptions = this.passedOptions; - } - this.referContext.accept(options, this.modifiers); - } - } - break; - case SIP.C.NOTIFY: - if (this.referContext && this.referContext instanceof SIP.ReferClientContext && request.hasHeader('event') && request.getHeader('event') === 'refer') { - this.referContext.receiveNotify(request); - return; - } - request.reply(200, 'OK'); - this.emit('notify', request); - break; - } - }, - - /** - * Reception of Response for in-dialog INVITE - * @private - */ - receiveReinviteResponse: function receiveReinviteResponse(response) { - var self = this; - - if (this.status === C.STATUS_TERMINATED) { - return; - } - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - break; - case /^2[0-9]{2}$/.test(response.status_code): - this.status = C.STATUS_CONFIRMED; - - // 17.1.1.1 - For each final response that is received at the client transaction, the client transaction sends an ACK, - this.emit("ack", response.transaction.sendACK()); - this.pendingReinvite = false; - // TODO: All of these timers should move into the Transaction layer - SIP.Timers.clearTimeout(self.timers.invite2xxTimer); - if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) { - this.logger.error('2XX response received to re-invite but did not have a description'); - this.emit('renegotiationError', new SIP.Exceptions.RenegotiationError('2XX response received to re-invite but did not have a description')); - - break; - } - - this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).catch(function onFailure(e) { - self.logger.error('Could not set the description in 2XX response'); - self.logger.error(e); - self.emit('renegotiationError', e); - self.sendRequest(SIP.C.BYE, { - extraHeaders: [SIP.Utils.getReasonHeaderValue(488, 'Not Acceptable Here')] - }); - }); - break; - default: - this.disableRenegotiation = true; - this.pendingReinvite = false; - this.logger.log('Received a non 1XX or 2XX response to a re-invite'); - this.emit('renegotiationError', new SIP.Exceptions.RenegotiationError('Invalid response to a re-invite')); - } - }, - - acceptAndTerminate: function acceptAndTerminate(response, status_code, reason_phrase) { - var extraHeaders = []; - - if (status_code) { - extraHeaders.push('Reason: ' + SIP.Utils.getReasonHeaderValue(status_code, reason_phrase)); - } - - // An error on dialog creation will fire 'failed' event - if (this.dialog || this.createDialog(response, 'UAC')) { - this.emit("ack", response.transaction.sendACK()); - this.sendRequest(SIP.C.BYE, { - extraHeaders: extraHeaders - }); - } - - return this; - }, - - /** - * RFC3261 13.3.1.4 - * Response retransmissions cannot be accomplished by transaction layer - * since it is destroyed when receiving the first 2xx answer - */ - setInvite2xxTimer: function setInvite2xxTimer(request, description) { - var self = this, - timeout = SIP.Timers.T1; - - this.timers.invite2xxTimer = SIP.Timers.setTimeout(function invite2xxRetransmission() { - if (self.status !== C.STATUS_WAITING_FOR_ACK) { - return; - } - - self.logger.log('no ACK received, attempting to retransmit OK'); - - var extraHeaders = ['Contact: ' + self.contact]; - - request.reply(200, null, extraHeaders, description); - - timeout = Math.min(timeout * 2, SIP.Timers.T2); - - self.timers.invite2xxTimer = SIP.Timers.setTimeout(invite2xxRetransmission, timeout); - }, timeout); - }, - - /** - * RFC3261 14.2 - * If a UAS generates a 2xx response and never receives an ACK, - * it SHOULD generate a BYE to terminate the dialog. - */ - setACKTimer: function setACKTimer() { - var self = this; - - this.timers.ackTimer = SIP.Timers.setTimeout(function () { - if (self.status === C.STATUS_WAITING_FOR_ACK) { - self.logger.log('no ACK received for an extended period of time, terminating the call'); - SIP.Timers.clearTimeout(self.timers.invite2xxTimer); - self.sendRequest(SIP.C.BYE); - self.terminated(null, SIP.C.causes.NO_ACK); - } - }, SIP.Timers.TIMER_H); - }, - - /* - * @private - */ - onTransportError: function onTransportError() { - if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.CONNECTION_ERROR); - } - }, - - onRequestTimeout: function onRequestTimeout() { - if (this.status === C.STATUS_CONFIRMED) { - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } else if (this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.REQUEST_TIMEOUT); - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } - }, - - onDialogError: function onDialogError(response) { - if (this.status === C.STATUS_CONFIRMED) { - this.terminated(response, SIP.C.causes.DIALOG_ERROR); - } else if (this.status !== C.STATUS_TERMINATED) { - this.failed(response, SIP.C.causes.DIALOG_ERROR); - this.terminated(response, SIP.C.causes.DIALOG_ERROR); - } - }, - - /** - * @private - */ - - failed: function failed(response, cause) { - if (this.status === C.STATUS_TERMINATED) { - return this; - } - this.emit('failed', response || null, cause || null); - return this; - }, - - rejected: function rejected(response, cause) { - this.emit('rejected', response || null, cause || null); - return this; - }, - - canceled: function canceled() { - this.emit('cancel'); - return this; - }, - - accepted: function accepted(response, cause) { - cause = SIP.Utils.getReasonPhrase(response && response.status_code, cause); - - this.startTime = new Date(); - - if (this.replacee) { - this.replacee.emit('replaced', this); - this.replacee.terminate(); - } - this.emit('accepted', response, cause); - return this; - }, - - terminated: function terminated(message, cause) { - if (this.status === C.STATUS_TERMINATED) { - return this; - } - - this.endTime = new Date(); - - this.close(); - this.emit('terminated', message || null, cause || null); - return this; - }, - - connecting: function connecting(request) { - this.emit('connecting', { request: request }); - return this; - } - }; - - Session.C = C; - SIP.Session = Session; - - InviteServerContext = function InviteServerContext(ua, request) { - var expires, - self = this, - contentType = request.getHeader('Content-Type'), - contentDisp = request.parseHeader('Content-Disposition'); - - SIP.Utils.augment(this, SIP.ServerContext, [ua, request]); - SIP.Utils.augment(this, SIP.Session, [ua.configuration.sessionDescriptionHandlerFactory]); - - if (contentDisp && contentDisp.type === 'render') { - this.renderbody = request.body; - this.rendertype = contentType; - } - - this.status = C.STATUS_INVITE_RECEIVED; - this.from_tag = request.from_tag; - this.id = request.call_id + this.from_tag; - this.request = request; - this.contact = this.ua.contact.toString(); - - this.receiveNonInviteResponse = function () {}; // intentional no-op - - this.logger = ua.getLogger('sip.inviteservercontext', this.id); - - //Save the session into the ua sessions collection. - this.ua.sessions[this.id] = this; - - //Get the Expires header value if exists - if (request.hasHeader('expires')) { - expires = request.getHeader('expires') * 1000; - } - - //Set 100rel if necessary - function set100rel(h, c) { - if (request.hasHeader(h) && request.getHeader(h).toLowerCase().indexOf('100rel') >= 0) { - self.rel100 = c; - } - } - set100rel('require', SIP.C.supported.REQUIRED); - set100rel('supported', SIP.C.supported.SUPPORTED); - - /* Set the to_tag before - * replying a response code that will create a dialog. - */ - request.to_tag = SIP.Utils.newTag(); - - // An error on dialog creation will fire 'failed' event - if (!this.createDialog(request, 'UAS', true)) { - request.reply(500, 'Missing Contact header field'); - return; - } - - var options = { extraHeaders: ['Contact: ' + self.contact] }; - - if (self.rel100 !== SIP.C.supported.REQUIRED) { - self.progress(options); - } - self.status = C.STATUS_WAITING_FOR_ANSWER; - - // Set userNoAnswerTimer - self.timers.userNoAnswerTimer = SIP.Timers.setTimeout(function () { - request.reply(408); - self.failed(request, SIP.C.causes.NO_ANSWER); - self.terminated(request, SIP.C.causes.NO_ANSWER); - }, self.ua.configuration.noAnswerTimeout); - - /* Set expiresTimer - * RFC3261 13.3.1 - */ - if (expires) { - self.timers.expiresTimer = SIP.Timers.setTimeout(function () { - if (self.status === C.STATUS_WAITING_FOR_ANSWER) { - request.reply(487); - self.failed(request, SIP.C.causes.EXPIRES); - self.terminated(request, SIP.C.causes.EXPIRES); - } - }, expires); - } - }; - - InviteServerContext.prototype = { - reject: function reject(options) { - // Check Session Status - if (this.status === C.STATUS_TERMINATED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - this.logger.log('rejecting RTCSession'); - - SIP.ServerContext.prototype.reject.call(this, options); - return this.terminated(); - }, - - terminate: function terminate(options) { - options = options || {}; - - var extraHeaders = (options.extraHeaders || []).slice(), - body = options.body, - dialog, - self = this; - - if (this.status === C.STATUS_WAITING_FOR_ACK && this.request.server_transaction.state !== SIP.Transactions.C.STATUS_TERMINATED) { - dialog = this.dialog; - - this.receiveRequest = function (request) { - if (request.method === SIP.C.ACK) { - this.sendRequest(SIP.C.BYE, { - extraHeaders: extraHeaders, - body: body - }); - dialog.terminate(); - } - }; - - this.request.server_transaction.on('stateChanged', function () { - if (this.state === SIP.Transactions.C.STATUS_TERMINATED && this.dialog) { - this.request = new SIP.OutgoingRequest(SIP.C.BYE, this.dialog.remote_target, this.ua, { - 'cseq': this.dialog.local_seqnum += 1, - 'call_id': this.dialog.id.call_id, - 'from_uri': this.dialog.local_uri, - 'from_tag': this.dialog.id.local_tag, - 'to_uri': this.dialog.remote_uri, - 'to_tag': this.dialog.id.remote_tag, - 'route_set': this.dialog.route_set - }, extraHeaders, body); - - new SIP.RequestSender({ - request: this.request, - onRequestTimeout: function onRequestTimeout() { - self.onRequestTimeout(); - }, - onTransportError: function onTransportError() { - self.onTransportError(); - }, - receiveResponse: function receiveResponse() { - return; - } - }, this.ua).send(); - dialog.terminate(); - } - }); - - this.emit('bye', this.request); - this.terminated(); - - // Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-) - this.dialog = dialog; - - // Restore the dialog into 'ua' so the ACK can reach 'this' session - this.ua.dialogs[dialog.id.toString()] = dialog; - } else if (this.status === C.STATUS_CONFIRMED) { - this.bye(options); - } else { - this.reject(options); - } - - return this; - }, - - /* - * @param {Object} [options.sessionDescriptionHandlerOptions] gets passed to SIP.SessionDescriptionHandler.getDescription as options - */ - progress: function progress(options) { - options = options || {}; - var statusCode = options.statusCode || 180, - reasonPhrase = options.reasonPhrase, - extraHeaders = (options.extraHeaders || []).slice(), - body = options.body, - response; - - if (statusCode < 100 || statusCode > 199) { - throw new TypeError('Invalid statusCode: ' + statusCode); - } - - if (this.isCanceled || this.status === C.STATUS_TERMINATED) { - return this; - } - - function do100rel() { - /* jshint validthis: true */ - statusCode = options.statusCode || 183; - - // Set status and add extra headers - this.status = C.STATUS_WAITING_FOR_PRACK; - extraHeaders.push('Contact: ' + this.contact); - extraHeaders.push('Require: 100rel'); - extraHeaders.push('RSeq: ' + Math.floor(Math.random() * 10000)); - - // Get the session description to add to preaccept with - this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers).then(function onSuccess(description) { - if (this.isCanceled || this.status === C.STATUS_TERMINATED) { - return; - } - - this.early_sdp = description.body; - this[this.hasOffer ? 'hasAnswer' : 'hasOffer'] = true; - - // Retransmit until we get a response or we time out (see prackTimer below) - var timeout = SIP.Timers.T1; - this.timers.rel1xxTimer = SIP.Timers.setTimeout(function rel1xxRetransmission() { - this.request.reply(statusCode, null, extraHeaders, description); - timeout *= 2; - this.timers.rel1xxTimer = SIP.Timers.setTimeout(rel1xxRetransmission.bind(this), timeout); - }.bind(this), timeout); - - // Timeout and reject INVITE if no response - this.timers.prackTimer = SIP.Timers.setTimeout(function () { - if (this.status !== C.STATUS_WAITING_FOR_PRACK) { - return; - } - - this.logger.log('no PRACK received, rejecting the call'); - SIP.Timers.clearTimeout(this.timers.rel1xxTimer); - this.request.reply(504); - this.terminated(null, SIP.C.causes.NO_PRACK); - }.bind(this), SIP.Timers.T1 * 64); - - // Send the initial response - response = this.request.reply(statusCode, reasonPhrase, extraHeaders, description); - this.emit('progress', response, reasonPhrase); - }.bind(this), function onFailure() { - this.request.reply(480); - this.failed(null, SIP.C.causes.WEBRTC_ERROR); - this.terminated(null, SIP.C.causes.WEBRTC_ERROR); - }.bind(this)); - } // end do100rel - - function normalReply() { - /* jshint validthis:true */ - response = this.request.reply(statusCode, reasonPhrase, extraHeaders, body); - this.emit('progress', response, reasonPhrase); - } - - if (options.statusCode !== 100 && (this.rel100 === SIP.C.supported.REQUIRED || this.rel100 === SIP.C.supported.SUPPORTED && options.rel100 || this.rel100 === SIP.C.supported.SUPPORTED && this.ua.configuration.rel100 === SIP.C.supported.REQUIRED)) { - this.sessionDescriptionHandler = this.setupSessionDescriptionHandler(); - if (this.sessionDescriptionHandler.hasDescription(this.request.getHeader('Content-Type'))) { - this.hasOffer = true; - this.sessionDescriptionHandler.setDescription(this.request.body, options.sessionDescriptionHandlerOptions, options.modifiers).then(do100rel.apply(this)).catch(function onFailure(e) { - this.logger.warn('invalid description'); - this.logger.warn(e); - this.failed(null, SIP.C.causes.WEBRTC_ERROR); - this.terminated(null, SIP.C.causes.WEBRTC_ERROR); - }.bind(this)); - } else { - do100rel.apply(this); - } - } else { - normalReply.apply(this); - } - return this; - }, - - /* - * @param {Object} [options.sessionDescriptionHandlerOptions] gets passed to SIP.SessionDescriptionHandler.getDescription as options - */ - accept: function accept(options) { - options = options || {}; - - this.onInfo = options.onInfo; - - var self = this, - request = this.request, - extraHeaders = (options.extraHeaders || []).slice(), - descriptionCreationSucceeded = function descriptionCreationSucceeded(description) { - var response, - - // run for reply success callback - replySucceeded = function replySucceeded() { - self.status = C.STATUS_WAITING_FOR_ACK; - - self.setInvite2xxTimer(request, description); - self.setACKTimer(); - }, - - - // run for reply failure callback - replyFailed = function replyFailed() { - self.failed(null, SIP.C.causes.CONNECTION_ERROR); - self.terminated(null, SIP.C.causes.CONNECTION_ERROR); - }; - - extraHeaders.push('Contact: ' + self.contact); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - if (!self.hasOffer) { - self.hasOffer = true; - } else { - self.hasAnswer = true; - } - response = request.reply(200, null, extraHeaders, description, replySucceeded, replyFailed); - if (self.status !== C.STATUS_TERMINATED) { - // Didn't fail - self.accepted(response, SIP.Utils.getReasonPhrase(200)); - } - }, - descriptionCreationFailed = function descriptionCreationFailed() { - // TODO: This should check the actual error and make sure it is an - // "expected" error. Otherwise it should throw. - if (self.status === C.STATUS_TERMINATED) { - return; - } - self.request.reply(480); - self.failed(null, SIP.C.causes.WEBRTC_ERROR); - self.terminated(null, SIP.C.causes.WEBRTC_ERROR); - }; - - // Check Session Status - if (this.status === C.STATUS_WAITING_FOR_PRACK) { - this.status = C.STATUS_ANSWERED_WAITING_FOR_PRACK; - return this; - } else if (this.status === C.STATUS_WAITING_FOR_ANSWER) { - this.status = C.STATUS_ANSWERED; - } else if (this.status !== C.STATUS_EARLY_MEDIA) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - // An error on dialog creation will fire 'failed' event - if (!this.createDialog(request, 'UAS')) { - request.reply(500, 'Missing Contact header field'); - return this; - } - - SIP.Timers.clearTimeout(this.timers.userNoAnswerTimer); - - if (this.status === C.STATUS_EARLY_MEDIA) { - descriptionCreationSucceeded({}); - } else { - this.sessionDescriptionHandler = this.setupSessionDescriptionHandler(); - if (this.request.getHeader('Content-Length') === '0' && !this.request.getHeader('Content-Type')) { - this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers).catch(descriptionCreationFailed).then(descriptionCreationSucceeded); - } else if (this.sessionDescriptionHandler.hasDescription(this.request.getHeader('Content-Type'))) { - this.hasOffer = true; - this.sessionDescriptionHandler.setDescription(this.request.body, options.sessionDescriptionHandlerOptions, options.modifiers).then(function () { - return this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers); - }.bind(this)).catch(descriptionCreationFailed).then(descriptionCreationSucceeded); - } else { - this.request.reply(415); - // TODO: Events - return; - } - } - - return this; - }, - - receiveRequest: function receiveRequest(request) { - - // ISC RECEIVE REQUEST - - function confirmSession() { - /* jshint validthis:true */ - var contentType, contentDisp; - - SIP.Timers.clearTimeout(this.timers.ackTimer); - SIP.Timers.clearTimeout(this.timers.invite2xxTimer); - this.status = C.STATUS_CONFIRMED; - - contentType = request.getHeader('Content-Type'); - contentDisp = request.getHeader('Content-Disposition'); - - if (contentDisp && contentDisp.type === 'render') { - this.renderbody = request.body; - this.rendertype = contentType; - } - - this.emit('confirmed', request); - } - - switch (request.method) { - case SIP.C.CANCEL: - /* RFC3261 15 States that a UAS may have accepted an invitation while a CANCEL - * was in progress and that the UAC MAY continue with the session established by - * any 2xx response, or MAY terminate with BYE. SIP does continue with the - * established session. So the CANCEL is processed only if the session is not yet - * established. - */ - - /* - * Terminate the whole session in case the user didn't accept (or yet to send the answer) nor reject the - *request opening the session. - */ - if (this.status === C.STATUS_WAITING_FOR_ANSWER || this.status === C.STATUS_WAITING_FOR_PRACK || this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK || this.status === C.STATUS_EARLY_MEDIA || this.status === C.STATUS_ANSWERED) { - - this.status = C.STATUS_CANCELED; - this.request.reply(487); - this.canceled(request); - this.rejected(request, SIP.C.causes.CANCELED); - this.failed(request, SIP.C.causes.CANCELED); - this.terminated(request, SIP.C.causes.CANCELED); - } - break; - case SIP.C.ACK: - if (this.status === C.STATUS_WAITING_FOR_ACK) { - if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) { - // ACK contains answer to an INVITE w/o SDP negotiation - this.hasAnswer = true; - this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then( - // TODO: Catch then .then - confirmSession.bind(this), function onFailure(e) { - this.logger.warn(e); - this.terminate({ - statusCode: '488', - reasonPhrase: 'Bad Media Description' - }); - this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - }.bind(this)); - } else { - confirmSession.apply(this); - } - } - break; - case SIP.C.PRACK: - if (this.status === C.STATUS_WAITING_FOR_PRACK || this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) { - if (!this.hasAnswer) { - this.sessionDescriptionHandler = this.setupSessionDescriptionHandler(); - if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) { - this.hasAnswer = true; - this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function onSuccess() { - SIP.Timers.clearTimeout(this.timers.rel1xxTimer); - SIP.Timers.clearTimeout(this.timers.prackTimer); - request.reply(200); - if (this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) { - this.status = C.STATUS_EARLY_MEDIA; - this.accept(); - } - this.status = C.STATUS_EARLY_MEDIA; - }.bind(this), function onFailure(e) { - this.logger.warn(e); - this.terminate({ - statusCode: '488', - reasonPhrase: 'Bad Media Description' - }); - this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - }.bind(this)); - } else { - this.terminate({ - statusCode: '488', - reasonPhrase: 'Bad Media Description' - }); - this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - } - } else { - SIP.Timers.clearTimeout(this.timers.rel1xxTimer); - SIP.Timers.clearTimeout(this.timers.prackTimer); - request.reply(200); - - if (this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) { - this.status = C.STATUS_EARLY_MEDIA; - this.accept(); - } - this.status = C.STATUS_EARLY_MEDIA; - } - } else if (this.status === C.STATUS_EARLY_MEDIA) { - request.reply(200); - } - break; - default: - Session.prototype.receiveRequest.apply(this, [request]); - break; - } - }, - - // Internal Function to setup the handler consistently - setupSessionDescriptionHandler: function setupSessionDescriptionHandler() { - if (this.sessionDescriptionHandler) { - return this.sessionDescriptionHandler; - } - return this.sessionDescriptionHandlerFactory(this, this.ua.configuration.sessionDescriptionHandlerFactoryOptions); - }, - - onTransportError: function onTransportError() { - if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.CONNECTION_ERROR); - } - }, - - onRequestTimeout: function onRequestTimeout() { - if (this.status === C.STATUS_CONFIRMED) { - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } else if (this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.REQUEST_TIMEOUT); - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } - } - - }; - - SIP.InviteServerContext = InviteServerContext; - - InviteClientContext = function InviteClientContext(ua, target, options, modifiers) { - options = options || {}; - this.passedOptions = options; // Save for later to use with refer - options.params = Object.create(options.params || Object.prototype); - - var extraHeaders = (options.extraHeaders || []).slice(), - sessionDescriptionHandlerFactory = ua.configuration.sessionDescriptionHandlerFactory; - - this.sessionDescriptionHandlerFactoryOptions = ua.configuration.sessionDescriptionHandlerFactoryOptions || {}; - this.sessionDescriptionHandlerOptions = options.sessionDescriptionHandlerOptions || {}; - this.modifiers = modifiers; - - this.inviteWithoutSdp = options.inviteWithoutSdp || false; - - // Set anonymous property - this.anonymous = options.anonymous || false; - - // Custom data to be sent either in INVITE or in ACK - this.renderbody = options.renderbody || null; - this.rendertype = options.rendertype || 'text/plain'; - - // Session parameter initialization - this.from_tag = SIP.Utils.newTag(); - options.params.from_tag = this.from_tag; - - /* Do not add ;ob in initial forming dialog requests if the registration over - * the current connection got a GRUU URI. - */ - this.contact = ua.contact.toString({ - anonymous: this.anonymous, - outbound: this.anonymous ? !ua.contact.temp_gruu : !ua.contact.pub_gruu - }); - - if (this.anonymous) { - options.params.from_displayName = 'Anonymous'; - options.params.from_uri = 'sip:anonymous@anonymous.invalid'; - - extraHeaders.push('P-Preferred-Identity: ' + ua.configuration.uri.toString()); - extraHeaders.push('Privacy: id'); - } - extraHeaders.push('Contact: ' + this.contact); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - if (this.inviteWithoutSdp && this.renderbody) { - extraHeaders.push('Content-Type: ' + this.rendertype); - extraHeaders.push('Content-Disposition: render;handling=optional'); - } - - if (ua.configuration.rel100 === SIP.C.supported.REQUIRED) { - extraHeaders.push('Require: 100rel'); - } - if (ua.configuration.replaces === SIP.C.supported.REQUIRED) { - extraHeaders.push('Require: replaces'); - } - - options.extraHeaders = extraHeaders; - - SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.INVITE, target, options]); - SIP.Utils.augment(this, SIP.Session, [sessionDescriptionHandlerFactory]); - - // Check Session Status - if (this.status !== C.STATUS_NULL) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - // OutgoingSession specific parameters - this.isCanceled = false; - this.received_100 = false; - - this.method = SIP.C.INVITE; - - this.receiveNonInviteResponse = this.receiveResponse; - this.receiveResponse = this.receiveInviteResponse; - - this.logger = ua.getLogger('sip.inviteclientcontext'); - - ua.applicants[this] = this; - - this.id = this.request.call_id + this.from_tag; - - this.onInfo = options.onInfo; - }; - - InviteClientContext.prototype = { - invite: function invite() { - var self = this; - - //Save the session into the ua sessions collection. - //Note: placing in constructor breaks call to request.cancel on close... User does not need this anyway - this.ua.sessions[this.id] = this; - - if (this.inviteWithoutSdp) { - //just send an invite with no sdp... - this.request.body = self.renderbody; - this.status = C.STATUS_INVITE_SENT; - this.send(); - } else { - //Initialize Media Session - this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions); - - this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions, this.modifiers).then(function onSuccess(description) { - if (self.isCanceled || self.status === C.STATUS_TERMINATED) { - return; - } - self.hasOffer = true; - self.request.body = description; - self.status = C.STATUS_INVITE_SENT; - self.send(); - }, function onFailure() { - if (self.status === C.STATUS_TERMINATED) { - return; - } - self.failed(null, SIP.C.causes.WEBRTC_ERROR); - self.terminated(null, SIP.C.causes.WEBRTC_ERROR); - }); - } - - return this; - }, - - receiveInviteResponse: function receiveInviteResponse(response) { - var cause, - session = this, - id = response.call_id + response.from_tag + response.to_tag, - extraHeaders = [], - options = {}; - - if (this.status === C.STATUS_TERMINATED || response.method !== SIP.C.INVITE) { - return; - } - - if (this.dialog && response.status_code >= 200 && response.status_code <= 299) { - if (id !== this.dialog.id.toString()) { - if (!this.createDialog(response, 'UAC', true)) { - return; - } - this.emit("ack", response.transaction.sendACK({ body: SIP.Utils.generateFakeSDP(response.body) })); - this.earlyDialogs[id].sendRequest(this, SIP.C.BYE); - - /* NOTE: This fails because the forking proxy does not recognize that an unanswerable - * leg (due to peerConnection limitations) has been answered first. If your forking - * proxy does not hang up all unanswered branches on the first branch answered, remove this. - */ - if (this.status !== C.STATUS_CONFIRMED) { - this.failed(response, SIP.C.causes.WEBRTC_ERROR); - this.terminated(response, SIP.C.causes.WEBRTC_ERROR); - } - return; - } else if (this.status === C.STATUS_CONFIRMED) { - this.emit("ack", response.transaction.sendACK()); - return; - } else if (!this.hasAnswer) { - // invite w/o sdp is waiting for callback - //an invite with sdp must go on, and hasAnswer is true - return; - } - } - - if (this.dialog && response.status_code < 200) { - /* - Early media has been set up with at least one other different branch, - but a final 2xx response hasn't been received - */ - if (this.dialog.pracked.indexOf(response.getHeader('rseq')) !== -1 || this.dialog.pracked[this.dialog.pracked.length - 1] >= response.getHeader('rseq') && this.dialog.pracked.length > 0) { - return; - } - - if (!this.earlyDialogs[id] && !this.createDialog(response, 'UAC', true)) { - return; - } - - if (this.earlyDialogs[id].pracked.indexOf(response.getHeader('rseq')) !== -1 || this.earlyDialogs[id].pracked[this.earlyDialogs[id].pracked.length - 1] >= response.getHeader('rseq') && this.earlyDialogs[id].pracked.length > 0) { - return; - } - - extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq')); - this.earlyDialogs[id].pracked.push(response.getHeader('rseq')); - - this.earlyDialogs[id].sendRequest(this, SIP.C.PRACK, { - extraHeaders: extraHeaders, - body: SIP.Utils.generateFakeSDP(response.body) - }); - return; - } - - // Proceed to cancellation if the user requested. - if (this.isCanceled) { - if (response.status_code >= 100 && response.status_code < 200) { - this.request.cancel(this.cancelReason, extraHeaders); - this.canceled(null); - } else if (response.status_code >= 200 && response.status_code < 299) { - this.acceptAndTerminate(response); - this.emit('bye', this.request); - } else if (response.status_code >= 300) { - cause = SIP.C.REASON_PHRASE[response.status_code] || SIP.C.causes.CANCELED; - this.rejected(response, cause); - this.failed(response, cause); - this.terminated(response, cause); - } - return; - } - - switch (true) { - case /^100$/.test(response.status_code): - this.received_100 = true; - this.emit('progress', response); - break; - case /^1[0-9]{2}$/.test(response.status_code): - // Do nothing with 1xx responses without To tag. - if (!response.to_tag) { - this.logger.warn('1xx response received without to tag'); - break; - } - - // Create Early Dialog if 1XX comes with contact - if (response.hasHeader('contact')) { - // An error on dialog creation will fire 'failed' event - if (!this.createDialog(response, 'UAC', true)) { - break; - } - } - - this.status = C.STATUS_1XX_RECEIVED; - - if (response.hasHeader('require') && response.getHeader('require').indexOf('100rel') !== -1) { - - // Do nothing if this.dialog is already confirmed - if (this.dialog || !this.earlyDialogs[id]) { - break; - } - - if (this.earlyDialogs[id].pracked.indexOf(response.getHeader('rseq')) !== -1 || this.earlyDialogs[id].pracked[this.earlyDialogs[id].pracked.length - 1] >= response.getHeader('rseq') && this.earlyDialogs[id].pracked.length > 0) { - return; - } - // TODO: This may be broken. It may have to be on the early dialog - this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions); - if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) { - extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq')); - this.earlyDialogs[id].pracked.push(response.getHeader('rseq')); - this.earlyDialogs[id].sendRequest(this, SIP.C.PRACK, { - extraHeaders: extraHeaders - }); - this.emit('progress', response); - } else if (this.hasOffer) { - if (!this.createDialog(response, 'UAC')) { - break; - } - this.hasAnswer = true; - this.dialog.pracked.push(response.getHeader('rseq')); - - this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function onSuccess() { - extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq')); - - session.sendRequest(SIP.C.PRACK, { - extraHeaders: extraHeaders, - receiveResponse: function receiveResponse() {} - }); - session.status = C.STATUS_EARLY_MEDIA; - session.emit('progress', response); - }, function onFailure(e) { - session.logger.warn(e); - session.acceptAndTerminate(response, 488, 'Not Acceptable Here'); - session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - }); - } else { - var earlyDialog = this.earlyDialogs[id]; - var earlyMedia = earlyDialog.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerOptions); - - earlyDialog.pracked.push(response.getHeader('rseq')); - - earlyMedia.setDescription(response.body, session.sessionDescriptionHandlerOptions, session.modifers).then(earlyMedia.getDescription.bind(earlyMedia, session.sessionDescriptionHandlerOptions, session.modifiers)).then(function onSuccess(description) { - extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq')); - earlyDialog.sendRequest(session, SIP.C.PRACK, { - extraHeaders: extraHeaders, - body: description - }); - session.status = C.STATUS_EARLY_MEDIA; - session.emit('progress', response); - }).catch(function onFailure(e) { - if (e instanceof SIP.Exceptions.GetDescriptionError) { - earlyDialog.pracked.push(response.getHeader('rseq')); - if (session.status === C.STATUS_TERMINATED) { - return; - } - session.failed(null, SIP.C.causes.WEBRTC_ERROR); - session.terminated(null, SIP.C.causes.WEBRTC_ERROR); - } else { - earlyDialog.pracked.splice(earlyDialog.pracked.indexOf(response.getHeader('rseq')), 1); - // Could not set remote description - session.logger.warn('invalid description'); - session.logger.warn(e); - } - }); - } - } else { - this.emit('progress', response); - } - break; - case /^2[0-9]{2}$/.test(response.status_code): - var cseq = this.request.cseq + ' ' + this.request.method; - if (cseq !== response.getHeader('cseq')) { - break; - } - - if (this.status === C.STATUS_EARLY_MEDIA && this.dialog) { - this.status = C.STATUS_CONFIRMED; - options = {}; - if (this.renderbody) { - extraHeaders.push('Content-Type: ' + this.rendertype); - options.extraHeaders = extraHeaders; - options.body = this.renderbody; - } - this.emit("ack", response.transaction.sendACK(options)); - this.accepted(response); - break; - } - // Do nothing if this.dialog is already confirmed - if (this.dialog) { - break; - } - - // This is an invite without sdp - if (!this.hasOffer) { - if (this.earlyDialogs[id] && this.earlyDialogs[id].sessionDescriptionHandler) { - //REVISIT - this.hasOffer = true; - this.hasAnswer = true; - this.sessionDescriptionHandler = this.earlyDialogs[id].sessionDescriptionHandler; - if (!this.createDialog(response, 'UAC')) { - break; - } - this.status = C.STATUS_CONFIRMED; - this.emit("ack", response.transaction.sendACK()); - - this.accepted(response); - } else { - this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions); - - if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) { - this.acceptAndTerminate(response, 400, 'Missing session description'); - this.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - break; - } - if (!this.createDialog(response, 'UAC')) { - break; - } - this.hasOffer = true; - this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler, this.sessionDescriptionHandlerOptions, this.modifiers)).then(function onSuccess(description) { - //var localMedia; - if (session.isCanceled || session.status === C.STATUS_TERMINATED) { - return; - } - - session.status = C.STATUS_CONFIRMED; - session.hasAnswer = true; - - session.emit("ack", response.transaction.sendACK({ body: description })); - session.accepted(response); - }).catch(function onFailure(e) { - if (e instanceof SIP.Exceptions.GetDescriptionError) { - // TODO do something here - session.logger.warn("there was a problem"); - } else { - session.logger.warn('invalid description'); - session.logger.warn(e); - session.acceptAndTerminate(response, 488, 'Invalid session description'); - session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - } - }); - } - } else if (this.hasAnswer) { - if (this.renderbody) { - extraHeaders.push('Content-Type: ' + session.rendertype); - options.extraHeaders = extraHeaders; - options.body = this.renderbody; - } - this.emit("ack", response.transaction.sendACK(options)); - } else { - if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) { - this.acceptAndTerminate(response, 400, 'Missing session description'); - this.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - break; - } - if (!this.createDialog(response, 'UAC')) { - break; - } - this.hasAnswer = true; - this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function onSuccess() { - var options = {}; - session.status = C.STATUS_CONFIRMED; - if (session.renderbody) { - extraHeaders.push('Content-Type: ' + session.rendertype); - options.extraHeaders = extraHeaders; - options.body = session.renderbody; - } - session.emit("ack", response.transaction.sendACK(options)); - session.accepted(response); - }, function onFailure(e) { - session.logger.warn(e); - session.acceptAndTerminate(response, 488, 'Not Acceptable Here'); - session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - }); - } - break; - default: - cause = SIP.Utils.sipErrorCause(response.status_code); - this.rejected(response, cause); - this.failed(response, cause); - this.terminated(response, cause); - } - }, - - cancel: function cancel(options) { - options = options || {}; - - options.extraHeaders = (options.extraHeaders || []).slice(); - - // Check Session Status - if (this.status === C.STATUS_TERMINATED || this.status === C.STATUS_CONFIRMED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - this.logger.log('canceling RTCSession'); - - var cancel_reason = SIP.Utils.getCancelReason(options.status_code, options.reason_phrase); - - // Check Session Status - if (this.status === C.STATUS_NULL || this.status === C.STATUS_INVITE_SENT && !this.received_100) { - this.isCanceled = true; - this.cancelReason = cancel_reason; - } else if (this.status === C.STATUS_INVITE_SENT || this.status === C.STATUS_1XX_RECEIVED || this.status === C.STATUS_EARLY_MEDIA) { - this.request.cancel(cancel_reason, options.extraHeaders); - } - - return this.canceled(); - }, - - terminate: function terminate(options) { - if (this.status === C.STATUS_TERMINATED) { - return this; - } - - if (this.status === C.STATUS_WAITING_FOR_ACK || this.status === C.STATUS_CONFIRMED) { - this.bye(options); - } else { - this.cancel(options); - } - - return this; - }, - - receiveRequest: function receiveRequest(request) { - // ICC RECEIVE REQUEST - - // Reject CANCELs - if (request.method === SIP.C.CANCEL) { - // TODO; make this a switch when it gets added - } - - if (request.method === SIP.C.ACK && this.status === C.STATUS_WAITING_FOR_ACK) { - - SIP.Timers.clearTimeout(this.timers.ackTimer); - SIP.Timers.clearTimeout(this.timers.invite2xxTimer); - this.status = C.STATUS_CONFIRMED; - - this.accepted(); - } - - return Session.prototype.receiveRequest.apply(this, [request]); - }, - - onTransportError: function onTransportError() { - if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.CONNECTION_ERROR); - } - }, - - onRequestTimeout: function onRequestTimeout() { - if (this.status === C.STATUS_CONFIRMED) { - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } else if (this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.REQUEST_TIMEOUT); - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } - } - - }; - - SIP.InviteClientContext = InviteClientContext; - - ReferClientContext = function ReferClientContext(ua, applicant, target, options) { - this.options = options || {}; - this.extraHeaders = (this.options.extraHeaders || []).slice(); - - if (ua === undefined || applicant === undefined || target === undefined) { - throw new TypeError('Not enough arguments'); - } - - SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.REFER, applicant.remoteIdentity.uri.toString(), options]); - - this.applicant = applicant; - - var withReplaces = target instanceof SIP.InviteServerContext || target instanceof SIP.InviteClientContext; - if (withReplaces) { - // Attended Transfer - // All of these fields should be defined based on the check above - this.target = '"' + target.remoteIdentity.friendlyName + '" ' + '<' + target.dialog.remote_target.toString() + '?Replaces=' + target.dialog.id.call_id + '%3Bto-tag%3D' + target.dialog.id.remote_tag + '%3Bfrom-tag%3D' + target.dialog.id.local_tag + '>'; - } else { - // Blind Transfer - // Refer-To: - try { - this.target = SIP.Grammar.parse(target, 'Refer_To').uri || target; - } catch (e) { - this.logger.debug(".refer() cannot parse Refer_To from", target); - this.logger.debug("...falling through to normalizeTarget()"); - } - - // Check target validity - this.target = this.ua.normalizeTarget(this.target); - if (!this.target) { - throw new TypeError('Invalid target: ' + target); - } - } - - if (this.ua) { - this.extraHeaders.push('Referred-By: <' + this.ua.configuration.uri + '>'); - } - // TODO: Check that this is correct isc/icc - this.extraHeaders.push('Contact: ' + applicant.contact); - this.extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - this.extraHeaders.push('Refer-To: ' + this.target); - }; - - ReferClientContext.prototype = { - - refer: function refer(options) { - options = options || {}; - - var extraHeaders = (this.extraHeaders || []).slice(); - if (options.extraHeaders) { - extraHeaders.concat(options.extraHeaders); - } - - this.applicant.sendRequest(SIP.C.REFER, { - extraHeaders: this.extraHeaders, - receiveResponse: function (response) { - if (/^1[0-9]{2}$/.test(response.status_code)) { - this.emit('referRequestProgress', this); - } else if (/^2[0-9]{2}$/.test(response.status_code)) { - this.emit('referRequestAccepted', this); - } else if (/^[4-6][0-9]{2}$/.test(response.status_code)) { - this.emit('referRequestRejected', this); - } - if (options.receiveResponse) { - options.receiveResponse(response); - } - }.bind(this) - }); - return this; - }, - - receiveNotify: function receiveNotify(request) { - // If we can correctly handle this, then we need to send a 200 OK! - if (request.hasHeader('Content-Type') && request.getHeader('Content-Type').search(/^message\/sipfrag/) !== -1) { - var messageBody = SIP.Grammar.parse(request.body, 'sipfrag'); - if (messageBody === -1) { - request.reply(489, 'Bad Event'); - return; - } - switch (true) { - case /^1[0-9]{2}$/.test(messageBody.status_code): - this.emit('referProgress', this); - break; - case /^2[0-9]{2}$/.test(messageBody.status_code): - this.emit('referAccepted', this); - if (!this.options.activeAfterTransfer && this.applicant.terminate) { - this.applicant.terminate(); - } - break; - default: - this.emit('referRejected', this); - break; - } - request.reply(200); - this.emit('notify', request); - return; - } - request.reply(489, 'Bad Event'); - } - }; - - SIP.ReferClientContext = ReferClientContext; - - ReferServerContext = function ReferServerContext(ua, request) { - SIP.Utils.augment(this, SIP.ServerContext, [ua, request]); - - this.ua = ua; - - this.status = C.STATUS_INVITE_RECEIVED; - this.from_tag = request.from_tag; - this.id = request.call_id + this.from_tag; - this.request = request; - this.contact = this.ua.contact.toString(); - - this.logger = ua.getLogger('sip.referservercontext', this.id); - - // RFC 3515 2.4.1 - if (!this.request.hasHeader('refer-to')) { - this.logger.warn('Invalid REFER packet. A refer-to header is required. Rejecting refer.'); - this.reject(); - return; - } - - this.referTo = this.request.parseHeader('refer-to'); - - // TODO: Must set expiration timer and send 202 if there is no response by then - - this.referredSession = this.ua.findSession(request); - - // Needed to send the NOTIFY's - this.cseq = Math.floor(Math.random() * 10000); - this.call_id = this.request.call_id; - this.from_uri = this.request.to.uri; - this.from_tag = this.request.to.parameters.tag; - this.remote_target = this.request.headers.Contact[0].parsed.uri; - this.to_uri = this.request.from.uri; - this.to_tag = this.request.from_tag; - this.route_set = this.request.getHeaders('record-route'); - - this.receiveNonInviteResponse = function () {}; - - if (this.request.hasHeader('referred-by')) { - this.referredBy = this.request.getHeader('referred-by'); - } - - if (this.referTo.uri.hasHeader('replaces')) { - this.replaces = this.referTo.uri.getHeader('replaces'); - } - - this.status = C.STATUS_WAITING_FOR_ANSWER; - }; - - ReferServerContext.prototype = { - - progress: function progress() { - if (this.status !== C.STATUS_WAITING_FOR_ANSWER) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - this.request.reply(100); - }, - - reject: function reject(options) { - if (this.status === C.STATUS_TERMINATED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - this.logger.log('Rejecting refer'); - this.status = C.STATUS_TERMINATED; - SIP.ServerContext.prototype.reject.call(this, options); - this.emit('referRequestRejected', this); - }, - - accept: function accept(options, modifiers) { - options = options || {}; - - if (this.status === C.STATUS_WAITING_FOR_ANSWER) { - this.status = C.STATUS_ANSWERED; - } else { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - this.request.reply(202, 'Accepted'); - this.emit('referRequestAccepted', this); - - if (options.followRefer) { - this.logger.log('Accepted refer, attempting to automatically follow it'); - - var target = this.referTo.uri; - if (!target.scheme.match("^sips?$")) { - this.logger.error('SIP.js can only automatically follow SIP refer target'); - this.reject(); - return; - } - - var inviteOptions = options.inviteOptions || {}; - var extraHeaders = (inviteOptions.extraHeaders || []).slice(); - if (this.replaces) { - // decodeURIComponent is a holdover from 2c086eb4. Not sure that it is actually necessary - extraHeaders.push('Replaces: ' + decodeURIComponent(this.replaces)); - } - - if (this.referredBy) { - extraHeaders.push('Referred-By: ' + this.referredBy); - } - - inviteOptions.extraHeaders = extraHeaders; - - target.clearHeaders(); - - this.targetSession = this.ua.invite(target, inviteOptions, modifiers); - - this.emit('referInviteSent', this); - - this.targetSession.once('progress', function () { - this.sendNotify('SIP/2.0 100 Trying'); - this.emit('referProgress', this); - if (this.referredSession) { - this.referredSession.emit('referProgress', this); - } - }.bind(this)); - this.targetSession.once('accepted', function () { - this.logger.log('Successfully followed the refer'); - this.sendNotify('SIP/2.0 200 OK'); - this.emit('referAccepted', this); - if (this.referredSession) { - this.referredSession.emit('referAccepted', this); - } - }.bind(this)); - - var referFailed = function referFailed(response) { - if (this.status === C.STATUS_TERMINATED) { - return; // No throw here because it is possible this gets called multiple times - } - this.logger.log('Refer was not successful. Resuming session'); - if (response && response.status_code === 429) { - this.logger.log('Alerting referrer that identity is required.'); - this.sendNotify('SIP/2.0 429 Provide Referrer Identity'); - return; - } - this.sendNotify('SIP/2.0 603 Declined'); - // Must change the status after sending the final Notify or it will not send due to check - this.status = C.STATUS_TERMINATED; - this.emit('referRejected', this); - if (this.referredSession) { - this.referredSession.emit('referRejected'); - } - }; - - this.targetSession.once('rejected', referFailed.bind(this)); - this.targetSession.once('failed', referFailed.bind(this)); - } else { - this.logger.log('Accepted refer, but did not automatically follow it'); - this.sendNotify('SIP/2.0 200 OK'); - this.emit('referAccepted', this); - if (this.referredSession) { - this.referredSession.emit('referAccepted', this); - } - } - }, - - sendNotify: function sendNotify(body) { - if (this.status !== C.STATUS_ANSWERED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - if (SIP.Grammar.parse(body, 'sipfrag') === -1) { - throw new Error('sipfrag body is required to send notify for refer'); - } - - var request = new SIP.OutgoingRequest(SIP.C.NOTIFY, this.remote_target, this.ua, { - cseq: this.cseq += 1, // randomly generated then incremented on each additional notify - call_id: this.call_id, // refer call_id - from_uri: this.from_uri, - from_tag: this.from_tag, - to_uri: this.to_uri, - to_tag: this.to_tag, - route_set: this.route_set - }, ['Event: refer', 'Subscription-State: terminated', 'Content-Type: message/sipfrag'], body); - - new SIP.RequestSender({ - request: request, - onRequestTimeout: function onRequestTimeout() { - return; - }, - onTransportError: function onTransportError() { - return; - }, - receiveResponse: function receiveResponse() { - return; - } - }, this.ua).send(); - } - }; - - SIP.ReferServerContext = ReferServerContext; -}; - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview DTMF - */ - -/** - * @class DTMF - * @param {SIP.Session} session - */ - -module.exports = function (SIP) { - - var _DTMF, - C = { - MIN_DURATION: 70, - MAX_DURATION: 6000, - DEFAULT_DURATION: 100, - MIN_INTER_TONE_GAP: 50, - DEFAULT_INTER_TONE_GAP: 500 - }; - - _DTMF = function DTMF(session, tone, options) { - var duration, interToneGap; - - if (tone === undefined) { - throw new TypeError('Not enough arguments'); - } - - this.logger = session.ua.getLogger('sip.invitecontext.dtmf', session.id); - this.owner = session; - this.direction = null; - - options = options || {}; - duration = options.duration || null; - interToneGap = options.interToneGap || null; - - // Check tone type - if (typeof tone === 'string') { - tone = tone.toUpperCase(); - } else if (typeof tone === 'number') { - tone = tone.toString(); - } else { - throw new TypeError('Invalid tone: ' + tone); - } - - // Check tone value - if (!tone.match(/^[0-9A-D#*]$/)) { - throw new TypeError('Invalid tone: ' + tone); - } else { - this.tone = tone; - } - - // Check duration - if (duration && !SIP.Utils.isDecimal(duration)) { - throw new TypeError('Invalid tone duration: ' + duration); - } else if (!duration) { - duration = _DTMF.C.DEFAULT_DURATION; - } else if (duration < _DTMF.C.MIN_DURATION) { - this.logger.warn('"duration" value is lower than the minimum allowed, setting it to ' + _DTMF.C.MIN_DURATION + ' milliseconds'); - duration = _DTMF.C.MIN_DURATION; - } else if (duration > _DTMF.C.MAX_DURATION) { - this.logger.warn('"duration" value is greater than the maximum allowed, setting it to ' + _DTMF.C.MAX_DURATION + ' milliseconds'); - duration = _DTMF.C.MAX_DURATION; - } else { - duration = Math.abs(duration); - } - this.duration = duration; - - // Check interToneGap - if (interToneGap && !SIP.Utils.isDecimal(interToneGap)) { - throw new TypeError('Invalid interToneGap: ' + interToneGap); - } else if (!interToneGap) { - interToneGap = _DTMF.C.DEFAULT_INTER_TONE_GAP; - } else if (interToneGap < _DTMF.C.MIN_INTER_TONE_GAP) { - this.logger.warn('"interToneGap" value is lower than the minimum allowed, setting it to ' + _DTMF.C.MIN_INTER_TONE_GAP + ' milliseconds'); - interToneGap = _DTMF.C.MIN_INTER_TONE_GAP; - } else { - interToneGap = Math.abs(interToneGap); - } - this.interToneGap = interToneGap; - }; - _DTMF.prototype = Object.create(SIP.EventEmitter.prototype); - - _DTMF.prototype.send = function (options) { - var extraHeaders, - body = {}; - - this.direction = 'outgoing'; - - // Check RTCSession Status - if (this.owner.status !== SIP.Session.C.STATUS_CONFIRMED && this.owner.status !== SIP.Session.C.STATUS_WAITING_FOR_ACK) { - throw new SIP.Exceptions.InvalidStateError(this.owner.status); - } - - // Get DTMF options - options = options || {}; - extraHeaders = options.extraHeaders ? options.extraHeaders.slice() : []; - - body.contentType = 'application/dtmf-relay'; - - body.body = "Signal= " + this.tone + "\r\n"; - body.body += "Duration= " + this.duration; - - this.request = this.owner.dialog.sendRequest(this, SIP.C.INFO, { - extraHeaders: extraHeaders, - body: body - }); - - this.owner.emit('dtmf', this.request, this); - }; - - /** - * @private - */ - _DTMF.prototype.receiveResponse = function (response) { - var cause; - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - // Ignore provisional responses. - break; - - case /^2[0-9]{2}$/.test(response.status_code): - this.emit('succeeded', { - originator: 'remote', - response: response - }); - break; - - default: - cause = SIP.Utils.sipErrorCause(response.status_code); - this.emit('failed', response, cause); - break; - } - }; - - /** - * @private - */ - _DTMF.prototype.onRequestTimeout = function () { - this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT); - this.owner.onRequestTimeout(); - }; - - /** - * @private - */ - _DTMF.prototype.onTransportError = function () { - this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR); - this.owner.onTransportError(); - }; - - /** - * @private - */ - _DTMF.prototype.onDialogError = function (response) { - this.emit('failed', response, SIP.C.causes.DIALOG_ERROR); - this.owner.onDialogError(response); - }; - - /** - * @private - */ - _DTMF.prototype.init_incoming = function (request) { - this.direction = 'incoming'; - this.request = request; - - request.reply(200); - - if (!this.tone || !this.duration) { - this.logger.warn('invalid INFO DTMF received, discarded'); - } else { - this.owner.emit('dtmf', request, this); - } - }; - - _DTMF.C = C; - return _DTMF; -}; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * @fileoverview SIP Subscriber (SIP-Specific Event Notifications RFC6665) - */ - -/** - * @augments SIP - * @class Class creating a SIP Subscription. - */ - -module.exports = function (SIP) { - SIP.Subscription = function (ua, target, event, options) { - options = Object.create(options || Object.prototype); - this.extraHeaders = options.extraHeaders = (options.extraHeaders || []).slice(); - - this.id = null; - this.state = 'init'; - - if (!event) { - throw new TypeError('Event necessary to create a subscription.'); - } else { - //TODO: check for valid events here probably make a list in SIP.C; or leave it up to app to check? - //The check may need to/should probably occur on the other side, - this.event = event; - } - - if (typeof options.expires !== 'number') { - ua.logger.warn('expires must be a number. Using default of 3600.'); - this.expires = 3600; - } else { - this.expires = options.expires; - } - this.requestedExpires = this.expires; - - options.extraHeaders.push('Event: ' + this.event); - options.extraHeaders.push('Expires: ' + this.expires); - - if (options.body) { - this.body = options.body; - } - - this.contact = ua.contact.toString(); - - options.extraHeaders.push('Contact: ' + this.contact); - options.extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.SUBSCRIBE, target, options]); - - this.logger = ua.getLogger('sip.subscription'); - - this.dialog = null; - this.timers = { N: null, sub_duration: null }; - this.errorCodes = [404, 405, 410, 416, 480, 481, 482, 483, 484, 485, 489, 501, 604]; - }; - - SIP.Subscription.prototype = { - subscribe: function subscribe() { - var sub = this; - - //these states point to an existing subscription, no subscribe is necessary - if (this.state === 'active') { - this.refresh(); - return this; - } else if (this.state === 'notify_wait') { - return this; - } - - SIP.Timers.clearTimeout(this.timers.sub_duration); - SIP.Timers.clearTimeout(this.timers.N); - this.timers.N = SIP.Timers.setTimeout(sub.timer_fire.bind(sub), SIP.Timers.TIMER_N); - - this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event] = this; - - this.send(); - - this.state = 'notify_wait'; - - return this; - }, - - refresh: function refresh() { - if (this.state === 'terminated' || this.state === 'pending' || this.state === 'notify_wait') { - return; - } - - this.dialog.sendRequest(this, SIP.C.SUBSCRIBE, { - extraHeaders: this.extraHeaders, - body: this.body - }); - }, - - receiveResponse: function receiveResponse(response) { - var expires, - sub = this, - cause = SIP.Utils.getReasonPhrase(response.status_code); - - if (this.state === 'notify_wait' && response.status_code >= 300 || this.state !== 'notify_wait' && this.errorCodes.indexOf(response.status_code) !== -1) { - this.failed(response, null); - } else if (/^2[0-9]{2}$/.test(response.status_code)) { - this.emit('accepted', response, cause); - //As we don't support RFC 5839 or other extensions where the NOTIFY is optional, timer N will not be cleared - //SIP.Timers.clearTimeout(this.timers.N); - - expires = response.getHeader('Expires'); - - if (expires && expires <= this.requestedExpires) { - // Preserve new expires value for subsequent requests - this.expires = expires; - this.timers.sub_duration = SIP.Timers.setTimeout(sub.refresh.bind(sub), expires * 900); - } else { - if (!expires) { - this.logger.warn('Expires header missing in a 200-class response to SUBSCRIBE'); - this.failed(response, SIP.C.EXPIRES_HEADER_MISSING); - } else { - this.logger.warn('Expires header in a 200-class response to SUBSCRIBE with a higher value than the one in the request'); - this.failed(response, SIP.C.INVALID_EXPIRES_HEADER); - } - } - } else if (response.statusCode > 300) { - this.emit('failed', response, cause); - this.emit('rejected', response, cause); - } - }, - - unsubscribe: function unsubscribe() { - var extraHeaders = [], - sub = this; - - this.state = 'terminated'; - - extraHeaders.push('Event: ' + this.event); - extraHeaders.push('Expires: 0'); - - extraHeaders.push('Contact: ' + this.contact); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - //makes sure expires isn't set, and other typical resubscribe behavior - this.receiveResponse = function () {}; - - this.dialog.sendRequest(this, this.method, { - extraHeaders: extraHeaders, - body: this.body - }); - - SIP.Timers.clearTimeout(this.timers.sub_duration); - SIP.Timers.clearTimeout(this.timers.N); - this.timers.N = SIP.Timers.setTimeout(sub.timer_fire.bind(sub), SIP.Timers.TIMER_N); - }, - - /** - * @private - */ - timer_fire: function timer_fire() { - if (this.state === 'terminated') { - this.terminateDialog(); - SIP.Timers.clearTimeout(this.timers.N); - SIP.Timers.clearTimeout(this.timers.sub_duration); - - delete this.ua.subscriptions[this.id]; - } else if (this.state === 'notify_wait' || this.state === 'pending') { - this.close(); - } else { - this.refresh(); - } - }, - - /** - * @private - */ - close: function close() { - if (this.state === 'notify_wait') { - this.state = 'terminated'; - SIP.Timers.clearTimeout(this.timers.N); - SIP.Timers.clearTimeout(this.timers.sub_duration); - this.receiveResponse = function () {}; - - delete this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event]; - } else if (this.state !== 'terminated') { - this.unsubscribe(); - } - }, - - /** - * @private - */ - createConfirmedDialog: function createConfirmedDialog(message, type) { - var dialog; - - this.terminateDialog(); - dialog = new SIP.Dialog(this, message, type); - dialog.invite_seqnum = this.request.cseq; - dialog.local_seqnum = this.request.cseq; - - if (!dialog.error) { - this.dialog = dialog; - return true; - } - // Dialog not created due to an error - else { - return false; - } - }, - - /** - * @private - */ - terminateDialog: function terminateDialog() { - if (this.dialog) { - delete this.ua.subscriptions[this.id]; - this.dialog.terminate(); - delete this.dialog; - } - }, - - /** - * @private - */ - receiveRequest: function receiveRequest(request) { - var sub_state, - sub = this; - - function setExpiresTimeout() { - if (sub_state.expires) { - SIP.Timers.clearTimeout(sub.timers.sub_duration); - sub_state.expires = Math.min(sub.expires, Math.max(sub_state.expires, 0)); - sub.timers.sub_duration = SIP.Timers.setTimeout(sub.refresh.bind(sub), sub_state.expires * 900); - } - } - - if (!this.matchEvent(request)) { - //checks event and subscription_state headers - request.reply(489); - return; - } - - if (!this.dialog) { - if (this.createConfirmedDialog(request, 'UAS')) { - this.id = this.dialog.id.toString(); - delete this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event]; - this.ua.subscriptions[this.id] = this; - // UPDATE ROUTE SET TO BE BACKWARDS COMPATIBLE? - } - } - - sub_state = request.parseHeader('Subscription-State'); - - request.reply(200, SIP.C.REASON_200); - - SIP.Timers.clearTimeout(this.timers.N); - - this.emit('notify', { request: request }); - - // if we've set state to terminated, no further processing should take place - // and we are only interested in cleaning up after the appropriate NOTIFY - if (this.state === 'terminated') { - if (sub_state.state === 'terminated') { - this.terminateDialog(); - SIP.Timers.clearTimeout(this.timers.N); - SIP.Timers.clearTimeout(this.timers.sub_duration); - - delete this.ua.subscriptions[this.id]; - } - return; - } - - switch (sub_state.state) { - case 'active': - this.state = 'active'; - setExpiresTimeout(); - break; - case 'pending': - if (this.state === 'notify_wait') { - setExpiresTimeout(); - } - this.state = 'pending'; - break; - case 'terminated': - SIP.Timers.clearTimeout(this.timers.sub_duration); - if (sub_state.reason) { - this.logger.log('terminating subscription with reason ' + sub_state.reason); - switch (sub_state.reason) { - case 'deactivated': - case 'timeout': - this.subscribe(); - return; - case 'probation': - case 'giveup': - if (sub_state.params && sub_state.params['retry-after']) { - this.timers.sub_duration = SIP.Timers.setTimeout(sub.subscribe.bind(sub), sub_state.params['retry-after']); - } else { - this.subscribe(); - } - return; - case 'rejected': - case 'noresource': - case 'invariant': - break; - } - } - this.close(); - break; - } - }, - - failed: function failed(response, cause) { - this.close(); - this.emit('failed', response, cause); - this.emit('rejected', response, cause); - return this; - }, - - onDialogError: function onDialogError(response) { - this.failed(response, SIP.C.causes.DIALOG_ERROR); - }, - - /** - * @private - */ - matchEvent: function matchEvent(request) { - var event; - - // Check mandatory header Event - if (!request.hasHeader('Event')) { - this.logger.warn('missing Event header'); - return false; - } - // Check mandatory header Subscription-State - if (!request.hasHeader('Subscription-State')) { - this.logger.warn('missing Subscription-State header'); - return false; - } - - // Check whether the event in NOTIFY matches the event in SUBSCRIBE - event = request.parseHeader('event').event; - - if (this.event !== event) { - this.logger.warn('event match failed'); - request.reply(481, 'Event Match Failed'); - return false; - } else { - return true; - } - } - }; -}; - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -/** - * @augments SIP - * @class Class creating a SIP User Agent. - * @param {function returning SIP.sessionDescriptionHandler} [configuration.sessionDescriptionHandlerFactory] - * A function will be invoked by each of the UA's Sessions to build the sessionDescriptionHandler for that Session. - * If no (or a falsy) value is provided, each Session will use a default (WebRTC) sessionDescriptionHandler. - * - * @param {Object} [configuration.media] gets passed to SIP.sessionDescriptionHandler.getDescription as mediaHint - */ - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -module.exports = function (SIP, environment) { - var UA, - C = { - // UA status codes - STATUS_INIT: 0, - STATUS_STARTING: 1, - STATUS_READY: 2, - STATUS_USER_CLOSED: 3, - STATUS_NOT_READY: 4, - - // UA error codes - CONFIGURATION_ERROR: 1, - NETWORK_ERROR: 2, - - ALLOWED_METHODS: ['ACK', 'CANCEL', 'INVITE', 'MESSAGE', 'BYE', 'OPTIONS', 'INFO', 'NOTIFY', 'REFER'], - - ACCEPTED_BODY_TYPES: ['application/sdp', 'application/dtmf-relay'], - - MAX_FORWARDS: 70, - TAG_LENGTH: 10 - }; - - UA = function UA(configuration) { - var self = this; - - // Helper function for forwarding events - function selfEmit(type) { - //registrationFailed handler is invoked with two arguments. Allow event handlers to be invoked with a variable no. of arguments - return self.emit.bind(self, type); - } - - // Set Accepted Body Types - C.ACCEPTED_BODY_TYPES = C.ACCEPTED_BODY_TYPES.toString(); - - this.log = new SIP.LoggerFactory(); - this.logger = this.getLogger('sip.ua'); - - this.cache = { - credentials: {} - }; - - this.configuration = {}; - this.dialogs = {}; - - //User actions outside any session/dialog (MESSAGE) - this.applicants = {}; - - this.data = {}; - this.sessions = {}; - this.subscriptions = {}; - this.earlySubscriptions = {}; - this.transport = null; - this.contact = null; - this.status = C.STATUS_INIT; - this.error = null; - this.transactions = { - nist: {}, - nict: {}, - ist: {}, - ict: {} - }; - - this.transportRecoverAttempts = 0; - this.transportRecoveryTimer = null; - - Object.defineProperties(this, { - transactionsCount: { - get: function get() { - var type, - transactions = ['nist', 'nict', 'ist', 'ict'], - count = 0; - - for (type in transactions) { - count += Object.keys(this.transactions[transactions[type]]).length; - } - - return count; - } - }, - - nictTransactionsCount: { - get: function get() { - return Object.keys(this.transactions['nict']).length; - } - }, - - nistTransactionsCount: { - get: function get() { - return Object.keys(this.transactions['nist']).length; - } - }, - - ictTransactionsCount: { - get: function get() { - return Object.keys(this.transactions['ict']).length; - } - }, - - istTransactionsCount: { - get: function get() { - return Object.keys(this.transactions['ist']).length; - } - } - }); - - /** - * Load configuration - * - * @throws {SIP.Exceptions.ConfigurationError} - * @throws {TypeError} - */ - - if (configuration === undefined) { - configuration = {}; - } else if (typeof configuration === 'string' || configuration instanceof String) { - configuration = { - uri: configuration - }; - } - - // Apply log configuration if present - if (configuration.log) { - if (configuration.log.hasOwnProperty('builtinEnabled')) { - this.log.builtinEnabled = configuration.log.builtinEnabled; - } - - if (configuration.log.hasOwnProperty('level')) { - this.log.level = configuration.log.level; - } - - if (configuration.log.hasOwnProperty('connector')) { - this.log.connector = configuration.log.connector; - } - } - - try { - this.loadConfig(configuration); - } catch (e) { - this.status = C.STATUS_NOT_READY; - this.error = C.CONFIGURATION_ERROR; - throw e; - } - - // Initialize registerContext - this.registerContext = new SIP.RegisterContext(this); - this.registerContext.on('failed', selfEmit('registrationFailed')); - this.registerContext.on('registered', selfEmit('registered')); - this.registerContext.on('unregistered', selfEmit('unregistered')); - - if (this.configuration.autostart) { - this.start(); - } - }; - UA.prototype = Object.create(SIP.EventEmitter.prototype); - - //================= - // High Level API - //================= - - UA.prototype.register = function (options) { - this.configuration.register = true; - this.registerContext.register(options); - - return this; - }; - - /** - * Unregister. - * - * @param {Boolean} [all] unregister all user bindings. - * - */ - UA.prototype.unregister = function (options) { - this.configuration.register = false; - - var context = this.registerContext; - this.afterConnected(context.unregister.bind(context, options)); - - return this; - }; - - UA.prototype.isRegistered = function () { - return this.registerContext.registered; - }; - - /** - * Connection state. - * @param {Boolean} - */ - UA.prototype.isConnected = function () { - return this.transport ? this.transport.connected : false; - }; - - UA.prototype.afterConnected = function afterConnected(callback) { - if (this.isConnected()) { - callback(); - } else { - this.once('connected', callback); - } - }; - - /** - * Returns a promise which resolves once the UA is connected. - */ - UA.prototype.waitForConnected = function () { - return new SIP.Utils.Promise(function (resolve) { - this.afterConnected(resolve); - }.bind(this)); - }; - - /** - * Make an outgoing call. - * - * @param {String} target - * @param {Object} views - * @param {Object} [options.media] gets passed to SIP.sessionDescriptionHandler.getDescription as mediaHint - * - * @throws {TypeError} - * - */ - UA.prototype.invite = function (target, options, modifiers) { - var context = new SIP.InviteClientContext(this, target, options, modifiers); - - // Delay sending actual invite until the next 'tick' if we are already - // connected, so that API consumers can register to events fired by the - // the session. - this.waitForConnected().then(function () { - context.invite(); - this.emit('inviteSent', context); - }.bind(this)); - return context; - }; - - UA.prototype.subscribe = function (target, event, options) { - var sub = new SIP.Subscription(this, target, event, options); - - this.afterConnected(sub.subscribe.bind(sub)); - return sub; - }; - - /** - * Send a message. - * - * @param {String} target - * @param {String} body - * @param {Object} [options] - * - * @throws {TypeError} - * - */ - UA.prototype.message = function (target, body, options) { - if (body === undefined) { - throw new TypeError('Not enough arguments'); - } - - // There is no Message module, so it is okay that the UA handles defaults here. - options = Object.create(options || Object.prototype); - options.contentType || (options.contentType = 'text/plain'); - options.body = body; - - return this.request(SIP.C.MESSAGE, target, options); - }; - - UA.prototype.request = function (method, target, options) { - var req = new SIP.ClientContext(this, method, target, options); - - this.afterConnected(req.send.bind(req)); - return req; - }; - - /** - * Gracefully close. - * - */ - UA.prototype.stop = function () { - var session, - subscription, - applicant, - ua = this; - - function transactionsListener() { - if (ua.nistTransactionsCount === 0 && ua.nictTransactionsCount === 0) { - ua.removeListener('transactionDestroyed', transactionsListener); - ua.transport.disconnect(); - } - } - - this.logger.log('user requested closure...'); - - if (this.status === C.STATUS_USER_CLOSED) { - this.logger.warn('UA already closed'); - return this; - } - - // Clear transportRecoveryTimer - SIP.Timers.clearTimeout(this.transportRecoveryTimer); - - // Close registerContext - this.logger.log('closing registerContext'); - this.registerContext.close(); - - // Run _terminate_ on every Session - for (session in this.sessions) { - this.logger.log('closing session ' + session); - this.sessions[session].terminate(); - } - - //Run _close_ on every confirmed Subscription - for (subscription in this.subscriptions) { - this.logger.log('unsubscribing from subscription ' + subscription); - this.subscriptions[subscription].close(); - } - - //Run _close_ on every early Subscription - for (subscription in this.earlySubscriptions) { - this.logger.log('unsubscribing from early subscription ' + subscription); - this.earlySubscriptions[subscription].close(); - } - - // Run _close_ on every applicant - for (applicant in this.applicants) { - this.applicants[applicant].close(); - } - - this.status = C.STATUS_USER_CLOSED; - - /* - * If the remaining transactions are all INVITE transactions, there is no need to - * wait anymore because every session has already been closed by this method. - * - locally originated sessions where terminated (CANCEL or BYE) - * - remotely originated sessions where rejected (4XX) or terminated (BYE) - * Remaining INVITE transactions belong tho sessions that where answered. This are in - * 'accepted' state due to timers 'L' and 'M' defined in [RFC 6026] - */ - if (this.nistTransactionsCount === 0 && this.nictTransactionsCount === 0) { - this.transport.disconnect(); - } else { - this.on('transactionDestroyed', transactionsListener); - } - - if (typeof environment.removeEventListener === 'function') { - // Google Chrome Packaged Apps don't allow 'unload' listeners: - // unload is not available in packaged apps - if (!(global.chrome && global.chrome.app && global.chrome.app.runtime)) { - environment.removeEventListener('unload', this.environListener); - } - } - - return this; - }; - - /** - * Connect to the WS server if status = STATUS_INIT. - * Resume UA after being closed. - * - */ - UA.prototype.start = function () { - var server; - - this.logger.log('user requested startup...'); - if (this.status === C.STATUS_INIT) { - server = this.getNextWsServer(); - this.status = C.STATUS_STARTING; - new SIP.Transport(this, server); - } else if (this.status === C.STATUS_USER_CLOSED) { - this.logger.log('resuming'); - this.status = C.STATUS_READY; - this.transport.connect(); - } else if (this.status === C.STATUS_STARTING) { - this.logger.log('UA is in STARTING status, not opening new connection'); - } else if (this.status === C.STATUS_READY) { - this.logger.log('UA is in READY status, not resuming'); - } else { - this.logger.error('Connection is down. Auto-Recovery system is trying to connect'); - } - - if (this.configuration.autostop && typeof environment.addEventListener === 'function') { - // Google Chrome Packaged Apps don't allow 'unload' listeners: - // unload is not available in packaged apps - if (!(global.chrome && global.chrome.app && global.chrome.app.runtime)) { - this.environListener = this.stop.bind(this); - environment.addEventListener('unload', this.environListener); - } - } - - return this; - }; - - /** - * Normalize a string into a valid SIP request URI - * - * @param {String} target - * - * @returns {SIP.URI|undefined} - */ - UA.prototype.normalizeTarget = function (target) { - return SIP.Utils.normalizeTarget(target, this.configuration.hostportParams); - }; - - //=============================== - // Private (For internal use) - //=============================== - - UA.prototype.saveCredentials = function (credentials) { - this.cache.credentials[credentials.realm] = this.cache.credentials[credentials.realm] || {}; - this.cache.credentials[credentials.realm][credentials.uri] = credentials; - - return this; - }; - - UA.prototype.getCredentials = function (request) { - var realm, credentials; - - realm = request.ruri.host; - - if (this.cache.credentials[realm] && this.cache.credentials[realm][request.ruri]) { - credentials = this.cache.credentials[realm][request.ruri]; - credentials.method = request.method; - } - - return credentials; - }; - - UA.prototype.getLogger = function (category, label) { - return this.log.getLogger(category, label); - }; - - //============================== - // Event Handlers - //============================== - - /** - * Transport Close event - * @private - * @event - * @param {SIP.Transport} transport. - */ - UA.prototype.onTransportClosed = function (transport) { - // Run _onTransportError_ callback on every client transaction using _transport_ - var type, - idx, - length, - client_transactions = ['nict', 'ict', 'nist', 'ist']; - - transport.server.status = SIP.Transport.C.STATUS_DISCONNECTED; - this.logger.log('connection state set to ' + SIP.Transport.C.STATUS_DISCONNECTED); - - length = client_transactions.length; - for (type = 0; type < length; type++) { - for (idx in this.transactions[client_transactions[type]]) { - this.transactions[client_transactions[type]][idx].onTransportError(); - } - } - - // Close sessions if GRUU is not being used - if (!this.contact.pub_gruu) { - this.closeSessionsOnTransportError(); - } - }; - - /** - * Unrecoverable transport event. - * Connection reattempt logic has been done and didn't success. - * @private - * @event - * @param {SIP.Transport} transport. - */ - UA.prototype.onTransportError = function (transport) { - var server; - - this.logger.log('transport ' + transport.server.ws_uri + ' failed | connection state set to ' + SIP.Transport.C.STATUS_ERROR); - - // Close sessions. - //Mark this transport as 'down' - transport.server.status = SIP.Transport.C.STATUS_ERROR; - - this.emit('disconnected', { - transport: transport - }); - - // try the next transport if the UA isn't closed - if (this.status === C.STATUS_USER_CLOSED) { - return; - } - - server = this.getNextWsServer(); - - if (server) { - new SIP.Transport(this, server); - } else { - this.closeSessionsOnTransportError(); - if (!this.error || this.error !== C.NETWORK_ERROR) { - this.status = C.STATUS_NOT_READY; - this.error = C.NETWORK_ERROR; - } - // Transport Recovery process - this.recoverTransport(); - } - }; - - /** - * Transport connection event. - * @private - * @event - * @param {SIP.Transport} transport. - */ - UA.prototype.onTransportConnected = function (transport) { - this.transport = transport; - - // Reset transport recovery counter - this.transportRecoverAttempts = 0; - - transport.server.status = SIP.Transport.C.STATUS_READY; - this.logger.log('connection state set to ' + SIP.Transport.C.STATUS_READY); - - if (this.status === C.STATUS_USER_CLOSED) { - return; - } - - this.status = C.STATUS_READY; - this.error = null; - - if (this.configuration.register) { - this.configuration.authenticationFactory.initialize().then(function () { - this.registerContext.onTransportConnected(); - }.bind(this)); - } - - this.emit('connected', { - transport: transport - }); - }; - - /** - * Transport connecting event - * @private - * @param {SIP.Transport} transport. - * #param {Integer} attempts. - */ - UA.prototype.onTransportConnecting = function (transport, attempts) { - this.emit('connecting', { - transport: transport, - attempts: attempts - }); - }; - - /** - * new Transaction - * @private - * @param {SIP.Transaction} transaction. - */ - UA.prototype.newTransaction = function (transaction) { - this.transactions[transaction.type][transaction.id] = transaction; - this.emit('newTransaction', { transaction: transaction }); - }; - - /** - * destroy Transaction - * @private - * @param {SIP.Transaction} transaction. - */ - UA.prototype.destroyTransaction = function (transaction) { - delete this.transactions[transaction.type][transaction.id]; - this.emit('transactionDestroyed', { - transaction: transaction - }); - }; - - //========================= - // receiveRequest - //========================= - - /** - * Request reception - * @private - * @param {SIP.IncomingRequest} request. - */ - UA.prototype.receiveRequest = function (request) { - var dialog, - session, - message, - earlySubscription, - method = request.method, - replaces, - replacedDialog, - self = this; - - function ruriMatches(uri) { - return uri && uri.user === request.ruri.user; - } - - // Check that request URI points to us - if (!(ruriMatches(this.configuration.uri) || ruriMatches(this.contact.uri) || ruriMatches(this.contact.pub_gruu) || ruriMatches(this.contact.temp_gruu))) { - this.logger.warn('Request-URI does not point to us'); - if (request.method !== SIP.C.ACK) { - request.reply_sl(404); - } - return; - } - - // Check request URI scheme - if (request.ruri.scheme === SIP.C.SIPS) { - request.reply_sl(416); - return; - } - - // Check transaction - if (SIP.Transactions.checkTransaction(this, request)) { - return; - } - - /* RFC3261 12.2.2 - * Requests that do not change in any way the state of a dialog may be - * received within a dialog (for example, an OPTIONS request). - * They are processed as if they had been received outside the dialog. - */ - if (method === SIP.C.OPTIONS) { - new SIP.Transactions.NonInviteServerTransaction(request, this); - request.reply(200, null, ['Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString(), 'Accept: ' + C.ACCEPTED_BODY_TYPES]); - } else if (method === SIP.C.MESSAGE) { - message = new SIP.ServerContext(this, request); - message.body = request.body; - message.content_type = request.getHeader('Content-Type') || 'text/plain'; - - request.reply(200, null); - this.emit('message', message); - } else if (method !== SIP.C.INVITE && method !== SIP.C.ACK) { - // Let those methods pass through to normal processing for now. - new SIP.ServerContext(this, request); - } - - // Initial Request - if (!request.to_tag) { - switch (method) { - case SIP.C.INVITE: - replaces = this.configuration.replaces !== SIP.C.supported.UNSUPPORTED && request.parseHeader('replaces'); - - if (replaces) { - replacedDialog = this.dialogs[replaces.call_id + replaces.replaces_to_tag + replaces.replaces_from_tag]; - - if (!replacedDialog) { - //Replaced header without a matching dialog, reject - request.reply_sl(481, null); - return; - } else if (replacedDialog.owner.status === SIP.Session.C.STATUS_TERMINATED) { - request.reply_sl(603, null); - return; - } else if (replacedDialog.state === SIP.Dialog.C.STATUS_CONFIRMED && replaces.early_only) { - request.reply_sl(486, null); - return; - } - } - - session = new SIP.InviteServerContext(this, request); - session.replacee = replacedDialog && replacedDialog.owner; - self.emit('invite', session); - break; - case SIP.C.BYE: - // Out of dialog BYE received - request.reply(481); - break; - case SIP.C.CANCEL: - session = this.findSession(request); - if (session) { - session.receiveRequest(request); - } else { - this.logger.warn('received CANCEL request for a non existent session'); - } - break; - case SIP.C.ACK: - /* Absorb it. - * ACK request without a corresponding Invite Transaction - * and without To tag. - */ - break; - case SIP.C.NOTIFY: - if (this.configuration.allowLegacyNotifications && this.listeners('notify').length > 0) { - request.reply(200, null); - self.emit('notify', { request: request }); - } else { - request.reply(481, 'Subscription does not exist'); - } - break; - case SIP.C.REFER: - this.logger.log('Received an out of dialog refer'); - if (this.configuration.allowOutOfDialogRefers) { - this.logger.log('Allow out of dialog refers is enabled on the UA'); - var referContext = new SIP.ReferServerContext(this, request); - var hasReferListener = this.listeners('outOfDialogReferRequested').length; - if (hasReferListener) { - this.emit('outOfDialogReferRequested', referContext); - } else { - this.logger.log('No outOfDialogReferRequest listeners, automatically accepting and following the out of dialog refer'); - referContext.accept({ followRefer: true }); - } - break; - } - request.reply(405); - break; - default: - request.reply(405); - break; - } - } - // In-dialog request - else { - dialog = this.findDialog(request); - - if (dialog) { - if (method === SIP.C.INVITE) { - new SIP.Transactions.InviteServerTransaction(request, this); - } - dialog.receiveRequest(request); - } else if (method === SIP.C.NOTIFY) { - session = this.findSession(request); - earlySubscription = this.findEarlySubscription(request); - if (session) { - session.receiveRequest(request); - } else if (earlySubscription) { - earlySubscription.receiveRequest(request); - } else { - this.logger.warn('received NOTIFY request for a non existent session or subscription'); - request.reply(481, 'Subscription does not exist'); - } - } - /* RFC3261 12.2.2 - * Request with to tag, but no matching dialog found. - * Exception: ACK for an Invite request for which a dialog has not - * been created. - */ - else { - if (method !== SIP.C.ACK) { - request.reply(481); - } - } - } - }; - - //================= - // Utils - //================= - - /** - * Get the session to which the request belongs to, if any. - * @private - * @param {SIP.IncomingRequest} request. - * @returns {SIP.OutgoingSession|SIP.IncomingSession|null} - */ - UA.prototype.findSession = function (request) { - return this.sessions[request.call_id + request.from_tag] || this.sessions[request.call_id + request.to_tag] || null; - }; - - /** - * Get the dialog to which the request belongs to, if any. - * @private - * @param {SIP.IncomingRequest} - * @returns {SIP.Dialog|null} - */ - UA.prototype.findDialog = function (request) { - return this.dialogs[request.call_id + request.from_tag + request.to_tag] || this.dialogs[request.call_id + request.to_tag + request.from_tag] || null; - }; - - /** - * Get the subscription which has not been confirmed to which the request belongs to, if any - * @private - * @param {SIP.IncomingRequest} - * @returns {SIP.Subscription|null} - */ - UA.prototype.findEarlySubscription = function (request) { - return this.earlySubscriptions[request.call_id + request.to_tag + request.getHeader('event')] || null; - }; - - /** - * Retrieve the next server to which connect. - * @private - * @returns {Object} ws_server - */ - UA.prototype.getNextWsServer = function () { - // Order servers by weight - var idx, - length, - ws_server, - candidates = []; - - length = this.configuration.wsServers.length; - for (idx = 0; idx < length; idx++) { - ws_server = this.configuration.wsServers[idx]; - - if (ws_server.status === SIP.Transport.C.STATUS_ERROR) { - continue; - } else if (candidates.length === 0) { - candidates.push(ws_server); - } else if (ws_server.weight > candidates[0].weight) { - candidates = [ws_server]; - } else if (ws_server.weight === candidates[0].weight) { - candidates.push(ws_server); - } - } - - idx = Math.floor(Math.random() * candidates.length); - - return candidates[idx]; - }; - - /** - * Close all sessions on transport error. - * @private - */ - UA.prototype.closeSessionsOnTransportError = function () { - var idx; - - // Run _transportError_ for every Session - for (idx in this.sessions) { - this.sessions[idx].onTransportError(); - } - // Call registerContext _onTransportClosed_ - this.registerContext.onTransportClosed(); - }; - - UA.prototype.recoverTransport = function (ua) { - var idx, length, k, nextRetry, count, server; - - ua = ua || this; - count = ua.transportRecoverAttempts; - - length = ua.configuration.wsServers.length; - for (idx = 0; idx < length; idx++) { - ua.configuration.wsServers[idx].status = 0; - } - - server = ua.getNextWsServer(); - - k = Math.floor(Math.random() * Math.pow(2, count) + 1); - nextRetry = k * ua.configuration.connectionRecoveryMinInterval; - - if (nextRetry > ua.configuration.connectionRecoveryMaxInterval) { - this.logger.log('time for next connection attempt exceeds connectionRecoveryMaxInterval, resetting counter'); - nextRetry = ua.configuration.connectionRecoveryMinInterval; - count = 0; - } - - this.logger.log('next connection attempt in ' + nextRetry + ' seconds'); - - this.transportRecoveryTimer = SIP.Timers.setTimeout(function () { - ua.transportRecoverAttempts = count + 1; - new SIP.Transport(ua, server); - }, nextRetry * 1000); - }; - - function checkAuthenticationFactory(authenticationFactory) { - if (!(authenticationFactory instanceof Function)) { - return; - } - if (!authenticationFactory.initialize) { - authenticationFactory.initialize = function initialize() { - return SIP.Utils.Promise.resolve(); - }; - } - return authenticationFactory; - } - - /** - * Configuration load. - * @private - * returns {Boolean} - */ - UA.prototype.loadConfig = function (configuration) { - // Settings and default values - var parameter, - value, - checked_value, - hostportParams, - registrarServer, - settings = { - /* Host address - * Value to be set in Via sent_by and host part of Contact FQDN - */ - viaHost: SIP.Utils.createRandomToken(12) + '.invalid', - - uri: new SIP.URI('sip', 'anonymous.' + SIP.Utils.createRandomToken(6), 'anonymous.invalid', null, null), - wsServers: [{ - scheme: 'WSS', - sip_uri: '', - status: 0, - weight: 0, - ws_uri: 'wss://edge.sip.onsip.com' - }], - - //Custom Configuration Settings - custom: {}, - - //Display name - displayName: '', - - // Password - password: null, - - // Registration parameters - registerExpires: 600, - register: true, - registrarServer: null, - - // Transport related parameters - wsServerMaxReconnection: 3, - wsServerReconnectionTimeout: 4, - - connectionRecoveryMinInterval: 2, - connectionRecoveryMaxInterval: 30, - - keepAliveInterval: 0, - - extraSupported: [], - - usePreloadedRoute: false, - - //string to be inserted into User-Agent request header - userAgentString: SIP.C.USER_AGENT, - - // Session parameters - noAnswerTimeout: 60, - - // Logging parameters - traceSip: false, - - // Hacks - hackViaTcp: false, - hackIpInContact: false, - hackWssInTransport: false, - hackAllowUnregisteredOptionTags: false, - - // Session Description Handler Options - sessionDescriptionHandlerFactoryOptions: { - constraints: {}, - peerConnectionOptions: {} - }, - - contactName: SIP.Utils.createRandomToken(8), // user name in user part - contactTransport: 'ws', - forceRport: false, - - //autostarting - autostart: true, - autostop: true, - - //Reliable Provisional Responses - rel100: SIP.C.supported.UNSUPPORTED, - - // Replaces header (RFC 3891) - // http://tools.ietf.org/html/rfc3891 - replaces: SIP.C.supported.UNSUPPORTED, - - sessionDescriptionHandlerFactory: __webpack_require__(27)(SIP).defaultFactory, - - authenticationFactory: checkAuthenticationFactory(function authenticationFactory(ua) { - return new SIP.DigestAuthentication(ua); - }), - - allowLegacyNotifications: false, - - allowOutOfDialogRefers: false - }; - - // Pre-Configuration - function aliasUnderscored(parameter, logger) { - var underscored = parameter.replace(/([a-z][A-Z])/g, function (m) { - return m[0] + '_' + m[1].toLowerCase(); - }); - - if (parameter === underscored) { - return; - } - - var hasParameter = configuration.hasOwnProperty(parameter); - if (configuration.hasOwnProperty(underscored)) { - logger.warn(underscored + ' is deprecated, please use ' + parameter); - if (hasParameter) { - logger.warn(parameter + ' overriding ' + underscored); - } - } - - configuration[parameter] = hasParameter ? configuration[parameter] : configuration[underscored]; - } - - var configCheck = this.getConfigurationCheck(); - - // Check Mandatory parameters - for (parameter in configCheck.mandatory) { - aliasUnderscored(parameter, this.logger); - if (!configuration.hasOwnProperty(parameter)) { - throw new SIP.Exceptions.ConfigurationError(parameter); - } else { - value = configuration[parameter]; - checked_value = configCheck.mandatory[parameter](value); - if (checked_value !== undefined) { - settings[parameter] = checked_value; - } else { - throw new SIP.Exceptions.ConfigurationError(parameter, value); - } - } - } - - // Check Optional parameters - for (parameter in configCheck.optional) { - aliasUnderscored(parameter, this.logger); - if (configuration.hasOwnProperty(parameter)) { - value = configuration[parameter]; - - // If the parameter value is an empty array, but shouldn't be, apply its default value. - if (value instanceof Array && value.length === 0) { - continue; - } - - // If the parameter value is null, empty string, or undefined then apply its default value. - if (value === null || value === "" || value === undefined) { - continue; - } - // If it's a number with NaN value then also apply its default value. - // NOTE: JS does not allow "value === NaN", the following does the work: - else if (typeof value === 'number' && isNaN(value)) { - continue; - } - - checked_value = configCheck.optional[parameter](value); - if (checked_value !== undefined) { - settings[parameter] = checked_value; - } else { - throw new SIP.Exceptions.ConfigurationError(parameter, value); - } - } - } - - // Sanity Checks - - // Connection recovery intervals - if (settings.connectionRecoveryMaxInterval < settings.connectionRecoveryMinInterval) { - throw new SIP.Exceptions.ConfigurationError('connectionRecoveryMaxInterval', settings.connectionRecoveryMaxInterval); - } - - // Post Configuration Process - - // Allow passing 0 number as displayName. - if (settings.displayName === 0) { - settings.displayName = '0'; - } - - // Instance-id for GRUU - if (!settings.instanceId) { - settings.instanceId = SIP.Utils.newUUID(); - } - - // sipjsId instance parameter. Static random tag of length 5 - settings.sipjsId = SIP.Utils.createRandomToken(5); - - // String containing settings.uri without scheme and user. - hostportParams = settings.uri.clone(); - hostportParams.user = null; - settings.hostportParams = hostportParams.toRaw().replace(/^sip:/i, ''); - - /* Check whether authorizationUser is explicitly defined. - * Take 'settings.uri.user' value if not. - */ - if (!settings.authorizationUser) { - settings.authorizationUser = settings.uri.user; - } - - /* If no 'registrarServer' is set use the 'uri' value without user portion. */ - if (!settings.registrarServer) { - registrarServer = settings.uri.clone(); - registrarServer.user = null; - settings.registrarServer = registrarServer; - } - - // User noAnswerTimeout - settings.noAnswerTimeout = settings.noAnswerTimeout * 1000; - - // Via Host - if (settings.hackIpInContact) { - if (typeof settings.hackIpInContact === 'boolean') { - settings.viaHost = SIP.Utils.getRandomTestNetIP(); - } else if (typeof settings.hackIpInContact === 'string') { - settings.viaHost = settings.hackIpInContact; - } - } - - // Contact transport parameter - if (settings.hackWssInTransport) { - settings.contactTransport = 'wss'; - } - - this.contact = { - pub_gruu: null, - temp_gruu: null, - uri: new SIP.URI('sip', settings.contactName, settings.viaHost, null, { transport: settings.contactTransport }), - toString: function toString(options) { - options = options || {}; - - var anonymous = options.anonymous || null, - outbound = options.outbound || null, - contact = '<'; - - if (anonymous) { - contact += (this.temp_gruu || 'sip:anonymous@anonymous.invalid;transport=' + settings.contactTransport).toString(); - } else { - contact += (this.pub_gruu || this.uri).toString(); - } - - if (outbound) { - contact += ';ob'; - } - - contact += '>'; - - return contact; - } - }; - - var skeleton = {}; - // Fill the value of the configuration_skeleton - for (parameter in settings) { - skeleton[parameter] = { - value: settings[parameter], - writable: parameter === 'register' || parameter === 'custom', - configurable: false - }; - } - - Object.defineProperties(this.configuration, skeleton); - - this.logger.log('configuration parameters after validation:'); - for (parameter in settings) { - switch (parameter) { - case 'uri': - case 'registrarServer': - case 'sessionDescriptionHandlerFactory': - this.logger.log('· ' + parameter + ': ' + settings[parameter]); - break; - case 'password': - this.logger.log('· ' + parameter + ': ' + 'NOT SHOWN'); - break; - default: - this.logger.log('· ' + parameter + ': ' + JSON.stringify(settings[parameter])); - } - } - - return; - }; - - /** - * Configuration checker. - * @private - * @return {Boolean} - */ - UA.prototype.getConfigurationCheck = function () { - return { - mandatory: {}, - - optional: { - - uri: function uri(_uri) { - var parsed; - - if (!/^sip:/i.test(_uri)) { - _uri = SIP.C.SIP + ':' + _uri; - } - parsed = SIP.URI.parse(_uri); - - if (!parsed) { - return; - } else if (!parsed.user) { - return; - } else { - return parsed; - } - }, - - //Note: this function used to call 'this.logger.error' but calling 'this' with anything here is invalid - wsServers: function wsServers(_wsServers) { - var idx, length, url; - - /* Allow defining wsServers parameter as: - * String: "host" - * Array of Strings: ["host1", "host2"] - * Array of Objects: [{ws_uri:"host1", weight:1}, {ws_uri:"host2", weight:0}] - * Array of Objects and Strings: [{ws_uri:"host1"}, "host2"] - */ - if (typeof _wsServers === 'string') { - _wsServers = [{ ws_uri: _wsServers }]; - } else if (_wsServers instanceof Array) { - length = _wsServers.length; - for (idx = 0; idx < length; idx++) { - if (typeof _wsServers[idx] === 'string') { - _wsServers[idx] = { ws_uri: _wsServers[idx] }; - } - } - } else { - return; - } - - if (_wsServers.length === 0) { - return false; - } - - length = _wsServers.length; - for (idx = 0; idx < length; idx++) { - if (!_wsServers[idx].ws_uri) { - return; - } - if (_wsServers[idx].weight && !Number(_wsServers[idx].weight)) { - return; - } - - url = SIP.Grammar.parse(_wsServers[idx].ws_uri, 'absoluteURI'); - - if (url === -1) { - return; - } else if (['wss', 'ws', 'udp'].indexOf(url.scheme) < 0) { - return; - } else { - _wsServers[idx].sip_uri = ''; - - if (!_wsServers[idx].weight) { - _wsServers[idx].weight = 0; - } - - _wsServers[idx].status = 0; - _wsServers[idx].scheme = url.scheme.toUpperCase(); - } - } - return _wsServers; - }, - - authorizationUser: function authorizationUser(_authorizationUser) { - if (SIP.Grammar.parse('"' + _authorizationUser + '"', 'quoted_string') === -1) { - return; - } else { - return _authorizationUser; - } - }, - - connectionRecoveryMaxInterval: function connectionRecoveryMaxInterval(_connectionRecoveryMaxInterval) { - var value; - if (SIP.Utils.isDecimal(_connectionRecoveryMaxInterval)) { - value = Number(_connectionRecoveryMaxInterval); - if (value > 0) { - return value; - } - } - }, - - connectionRecoveryMinInterval: function connectionRecoveryMinInterval(_connectionRecoveryMinInterval) { - var value; - if (SIP.Utils.isDecimal(_connectionRecoveryMinInterval)) { - value = Number(_connectionRecoveryMinInterval); - if (value > 0) { - return value; - } - } - }, - - displayName: function displayName(_displayName) { - if (SIP.Grammar.parse('"' + _displayName + '"', 'displayName') === -1) { - return; - } else { - return _displayName; - } - }, - - hackViaTcp: function hackViaTcp(_hackViaTcp) { - if (typeof _hackViaTcp === 'boolean') { - return _hackViaTcp; - } - }, - - hackIpInContact: function hackIpInContact(_hackIpInContact) { - if (typeof _hackIpInContact === 'boolean') { - return _hackIpInContact; - } else if (typeof _hackIpInContact === 'string' && SIP.Grammar.parse(_hackIpInContact, 'host') !== -1) { - return _hackIpInContact; - } - }, - - hackWssInTransport: function hackWssInTransport(_hackWssInTransport) { - if (typeof _hackWssInTransport === 'boolean') { - return _hackWssInTransport; - } - }, - - hackAllowUnregisteredOptionTags: function hackAllowUnregisteredOptionTags(_hackAllowUnregisteredOptionTags) { - if (typeof _hackAllowUnregisteredOptionTags === 'boolean') { - return _hackAllowUnregisteredOptionTags; - } - }, - - contactTransport: function contactTransport(_contactTransport) { - if (typeof _contactTransport === 'string') { - return _contactTransport; - } - }, - - forceRport: function forceRport(_forceRport) { - if (typeof _forceRport === 'boolean') { - return _forceRport; - } - }, - - instanceId: function instanceId(_instanceId) { - if (typeof _instanceId !== 'string') { - return; - } - - if (/^uuid:/i.test(_instanceId)) { - _instanceId = _instanceId.substr(5); - } - - if (SIP.Grammar.parse(_instanceId, 'uuid') === -1) { - return; - } else { - return _instanceId; - } - }, - - keepAliveInterval: function keepAliveInterval(_keepAliveInterval) { - var value; - if (SIP.Utils.isDecimal(_keepAliveInterval)) { - value = Number(_keepAliveInterval); - if (value > 0) { - return value; - } - } - }, - - extraSupported: function extraSupported(optionTags) { - var idx, length; - - if (!(optionTags instanceof Array)) { - return; - } - - length = optionTags.length; - for (idx = 0; idx < length; idx++) { - if (typeof optionTags[idx] !== 'string') { - return; - } - } - - return optionTags; - }, - - noAnswerTimeout: function noAnswerTimeout(_noAnswerTimeout) { - var value; - if (SIP.Utils.isDecimal(_noAnswerTimeout)) { - value = Number(_noAnswerTimeout); - if (value > 0) { - return value; - } - } - }, - - password: function password(_password) { - return String(_password); - }, - - rel100: function rel100(_rel) { - if (_rel === SIP.C.supported.REQUIRED) { - return SIP.C.supported.REQUIRED; - } else if (_rel === SIP.C.supported.SUPPORTED) { - return SIP.C.supported.SUPPORTED; - } else { - return SIP.C.supported.UNSUPPORTED; - } - }, - - replaces: function replaces(_replaces) { - if (_replaces === SIP.C.supported.REQUIRED) { - return SIP.C.supported.REQUIRED; - } else if (_replaces === SIP.C.supported.SUPPORTED) { - return SIP.C.supported.SUPPORTED; - } else { - return SIP.C.supported.UNSUPPORTED; - } - }, - - register: function register(_register) { - if (typeof _register === 'boolean') { - return _register; - } - }, - - registerExpires: function registerExpires(_registerExpires) { - var value; - if (SIP.Utils.isDecimal(_registerExpires)) { - value = Number(_registerExpires); - if (value > 0) { - return value; - } - } - }, - - registrarServer: function registrarServer(_registrarServer) { - var parsed; - - if (typeof _registrarServer !== 'string') { - return; - } - - if (!/^sip:/i.test(_registrarServer)) { - _registrarServer = SIP.C.SIP + ':' + _registrarServer; - } - parsed = SIP.URI.parse(_registrarServer); - - if (!parsed) { - return; - } else if (parsed.user) { - return; - } else { - return parsed; - } - }, - - traceSip: function traceSip(_traceSip) { - if (typeof _traceSip === 'boolean') { - return _traceSip; - } - }, - - userAgentString: function userAgentString(_userAgentString) { - if (typeof _userAgentString === 'string') { - return _userAgentString; - } - }, - - usePreloadedRoute: function usePreloadedRoute(_usePreloadedRoute) { - if (typeof _usePreloadedRoute === 'boolean') { - return _usePreloadedRoute; - } - }, - - wsServerMaxReconnection: function wsServerMaxReconnection(_wsServerMaxReconnection) { - var value; - if (SIP.Utils.isDecimal(_wsServerMaxReconnection)) { - value = Number(_wsServerMaxReconnection); - if (value > 0) { - return value; - } - } - }, - - wsServerReconnectionTimeout: function wsServerReconnectionTimeout(_wsServerReconnectionTimeout) { - var value; - if (SIP.Utils.isDecimal(_wsServerReconnectionTimeout)) { - value = Number(_wsServerReconnectionTimeout); - if (value > 0) { - return value; - } - } - }, - - autostart: function autostart(_autostart) { - if (typeof _autostart === 'boolean') { - return _autostart; - } - }, - - autostop: function autostop(_autostop) { - if (typeof _autostop === 'boolean') { - return _autostop; - } - }, - - sessionDescriptionHandlerFactory: function sessionDescriptionHandlerFactory(_sessionDescriptionHandlerFactory) { - if (_sessionDescriptionHandlerFactory instanceof Function) { - return _sessionDescriptionHandlerFactory; - } - }, - - sessionDescriptionHandlerFactoryOptions: function sessionDescriptionHandlerFactoryOptions(options) { - if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object') { - return options; - } - }, - - authenticationFactory: checkAuthenticationFactory, - - allowLegacyNotifications: function allowLegacyNotifications(_allowLegacyNotifications) { - if (typeof _allowLegacyNotifications === 'boolean') { - return _allowLegacyNotifications; - } - }, - - custom: function custom(_custom) { - if ((typeof _custom === 'undefined' ? 'undefined' : _typeof(_custom)) === 'object') { - return _custom; - } - }, - - contactName: function contactName(_contactName) { - if (typeof _contactName === 'string') { - return _contactName; - } - } - } - }; - }; - - UA.C = C; - SIP.UA = UA; -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -/** - * @fileoverview SessionDescriptionHandler - */ - -/* SessionDescriptionHandler - * @class PeerConnection helper Class. - * @param {SIP.Session} session - * @param {Object} [options] - */ - -module.exports = function (SIP) { - - // Constructor - var SessionDescriptionHandler = function SessionDescriptionHandler(session, options) { - // TODO: Validate the options - this.options = options || {}; - - this.logger = session.ua.getLogger('sip.invitecontext.sessionDescriptionHandler', session.id); - this.session = session; - - this.CONTENT_TYPE = 'application/sdp'; - - this.modifiers = this.options.modifiers || []; - if (!Array.isArray(this.modifiers)) { - this.modifiers = [this.modifiers]; - } - - var environment = global.window || global; - this.WebRTC = { - MediaStream: environment.MediaStream, - getUserMedia: environment.navigator.mediaDevices.getUserMedia.bind(environment.navigator.mediaDevices), - RTCPeerConnection: environment.RTCPeerConnection, - RTCSessionDescription: environment.RTCSessionDescription - }; - - this.iceGatheringDeferred = null; - this.iceGatheringTimeout = false; - this.iceGatheringTimer = null; - - this.initPeerConnection(this.options.peerConnectionOptions); - - this.constraints = this.checkAndDefaultConstraints(this.options.constraints); - - this.session.emit('SessionDescriptionHandler-created', this); - }; - - /** - * @param {SIP.Session} session - * @param {Object} [options] - */ - - SessionDescriptionHandler.defaultFactory = function defaultFactory(session, options) { - return new SessionDescriptionHandler(session, options); - }; - - SessionDescriptionHandler.prototype = Object.create(SIP.SessionDescriptionHandler.prototype, { - // Functions the sesssion can use - - /** - * Destructor - */ - close: { writable: true, value: function value() { - this.logger.log('closing PeerConnection'); - // have to check signalingState since this.close() gets called multiple times - if (this.peerConnection && this.peerConnection.signalingState !== 'closed') { - if (this.peerConnection.getSenders) { - this.peerConnection.getSenders().forEach(function (sender) { - if (sender.track) { - sender.track.stop(); - } - }); - } else { - this.logger.warn('Using getLocalStreams which is deprecated'); - this.peerConnection.getLocalStreams().forEach(function (stream) { - stream.getTracks().forEach(function (track) { - track.stop(); - }); - }); - } - if (this.peerConnection.getReceivers) { - this.peerConnection.getReceivers().forEach(function (receiver) { - if (receiver.track) { - receiver.track.stop(); - } - }); - } else { - this.logger.warn('Using getRemoteStreams which is deprecated'); - this.peerConnection.getRemoteStreams().forEach(function (stream) { - stream.getTracks().forEach(function (track) { - track.stop(); - }); - }); - } - this.resetIceGatheringComplete(); - this.peerConnection.close(); - } - } }, - - /** - * Gets the local description from the underlying media implementation - * @param {Object} [options] Options object to be used by getDescription - * @param {MediaStreamConstraints} [options.constraints] MediaStreamConstraints https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints - * @param {Object} [options.peerConnectionOptions] If this is set it will recreate the peer connection with the new options - * @param {Array} [modifiers] Array with one time use description modifiers - * @returns {Promise} Promise that resolves with the local description to be used for the session - */ - getDescription: { writable: true, value: function value(options, modifiers) { - var self = this; - var shouldAcquireMedia = true; - - if (this.session.disableRenegotiation) { - this.logger.warn("The flag \"disableRenegotiation\" is set to true for this session description handler. We will not try to renegotiate."); - return SIP.Utils.Promise.reject(new SIP.Exceptions.RenegotiationError("disableRenegotiation flag set to true for this session description handler")); - } - - options = options || {}; - if (options.peerConnectionOptions) { - this.initPeerConnection(options.peerConnectionOptions); - } - - // Merge passed constraints with saved constraints and save - var newConstraints = Object.assign({}, this.constraints, options.constraints); - newConstraints = this.checkAndDefaultConstraints(newConstraints); - if (JSON.stringify(newConstraints) !== JSON.stringify(this.constraints)) { - this.constraints = newConstraints; - } else { - shouldAcquireMedia = false; - } - - modifiers = modifiers || []; - if (!Array.isArray(modifiers)) { - modifiers = [modifiers]; - } - modifiers = modifiers.concat(this.modifiers); - - // Check to see if the peerConnection already has a local description - if (!shouldAcquireMedia && this.peerConnection.localDescription && this.peerConnection.localDescription.sdp && this.peerConnection.localDescription.sdp !== '') { - return this.createOfferOrAnswer(options.RTCOfferOptions, modifiers).then(function (sdp) { - return { - body: sdp, - contentType: self.CONTENT_TYPE - }; - }); - } - - // GUM and set myself up - self.logger.log('acquiring local media'); - // TODO: Constraints should be named MediaStreamConstraints - return this.acquire(self.constraints).then(function acquireSucceeded(streams) { - self.logger.log('acquired local media streams'); - return streams; - }, function acquireFailed(err) { - self.logger.error('unable to acquire streams'); - self.logger.error(err); - throw err; - }).then(function addStreams(streams) { - try { - streams = [].concat(streams); - streams.forEach(function (stream) { - if (self.peerConnection.addTrack) { - stream.getTracks().forEach(function (track) { - self.peerConnection.addTrack(track, stream); - }); - } else { - // Chrome 59 does not support addTrack - self.peerConnection.addStream(stream); - } - }, this); - } catch (e) { - self.logger.error('error adding stream'); - self.logger.error(e); - return SIP.Utils.Promise.reject(e); - } - return SIP.Utils.Promise.resolve(); - }).then(function streamAdditionSucceeded() { - return self.createOfferOrAnswer(options.RTCOfferOptions, modifiers); - }).then(function (sdp) { - return { - body: sdp, - contentType: self.CONTENT_TYPE - }; - }).catch(function (e) { - this.session.disableRenegotiation = true; - throw e; - }); - } }, - - /** - * Check if the Session Description Handler can handle the Content-Type described by a SIP Message - * @param {String} contentType The content type that is in the SIP Message - * @returns {boolean} - */ - hasDescription: { writable: true, value: function hasDescription(contentType) { - return contentType === this.CONTENT_TYPE; - } }, - - /** - * The modifier that should be used when the session would like to place the call on hold - * @param {String} [sdp] The description that will be modified - * @returns {Promise} Promise that resolves with modified SDP - */ - holdModifier: { writable: true, value: function holdModifier(description) { - if (!/a=(sendrecv|sendonly|recvonly|inactive)/.test(description.sdp)) { - description.sdp = description.sdp.replace(/(m=[^\r]*\r\n)/g, '$1a=sendonly\r\n'); - } else { - description.sdp = description.sdp.replace(/a=sendrecv\r\n/g, 'a=sendonly\r\n'); - description.sdp = description.sdp.replace(/a=recvonly\r\n/g, 'a=inactive\r\n'); - } - return SIP.Utils.Promise.resolve(description); - } }, - - /** - * Set the remote description to the underlying media implementation - * @param {String} sessionDescription The description provided by a SIP message to be set on the media implementation - * @param {Object} [options] Options object to be used by getDescription - * @param {MediaStreamConstraints} [options.constraints] MediaStreamConstraints https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints - * @param {Object} [options.peerConnectionOptions] If this is set it will recreate the peer connection with the new options - * @param {Array} [modifiers] Array with one time use description modifiers - * @returns {Promise} Promise that resolves once the description is set - */ - setDescription: { writable: true, value: function setDescription(sessionDescription, options, modifiers) { - var self = this; - - // https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser - var isFirefox = typeof InstallTrigger !== 'undefined'; - if (!this.session.disableRenegotiation && isFirefox && this.peerConnection && this.isVideoHold(sessionDescription)) { - this.session.disableRenegotiation = true; - } - - if (this.session.disableRenegotiation) { - this.logger.warn("The flag \"disableRenegotiation\" is set to true for this session description handler. We will not try to renegotiate."); - return SIP.Utils.Promise.reject(new SIP.Exceptions.RenegotiationError("disableRenegotiation flag set to true for this session description handler")); - } - - options = options || {}; - if (options.peerConnectionOptions) { - this.initPeerConnection(options.peerConnectionOptions); - } - - // Merge passed constraints with saved constraints and save - this.constraints = Object.assign({}, this.constraints, options.constraints); - this.constraints = this.checkAndDefaultConstraints(this.constraints); - - modifiers = modifiers || []; - if (!Array.isArray(modifiers)) { - modifiers = [modifiers]; - } - modifiers = modifiers.concat(this.modifiers); - - var description = { - type: this.hasOffer('local') ? 'answer' : 'offer', - sdp: sessionDescription - }; - - return SIP.Utils.reducePromises(modifiers, description).catch(function modifierError(e) { - self.logger.error("The modifiers did not resolve successfully"); - self.logger.error(e); - throw e; - }).then(function (modifiedDescription) { - self.emit('setDescription', modifiedDescription); - return self.peerConnection.setRemoteDescription(new self.WebRTC.RTCSessionDescription(modifiedDescription)); - }).catch(function setRemoteDescriptionError(e) { - self.session.disableRenegotiation = true; - self.logger.error(e); - self.emit('peerConnection-setRemoteDescriptionFailed', e); - throw e; - }).then(function setRemoteDescriptionSuccess() { - if (self.peerConnection.getReceivers) { - self.emit('setRemoteDescription', self.peerConnection.getReceivers()); - } else { - self.emit('setRemoteDescription', self.peerConnection.getRemoteStreams()); - } - self.emit('confirmed', self); - }); - } }, - - // Internal functions - createOfferOrAnswer: { writable: true, value: function createOfferOrAnswer(RTCOfferOptions, modifiers) { - var self = this; - var methodName; - var pc = this.peerConnection; - - RTCOfferOptions = RTCOfferOptions || {}; - - methodName = self.hasOffer('remote') ? 'createAnswer' : 'createOffer'; - - return pc[methodName](RTCOfferOptions).catch(function methodError(e) { - self.emit('peerConnection-' + methodName + 'Failed', e); - throw e; - }).then(function (sdp) { - return SIP.Utils.reducePromises(modifiers, sdp); - }).then(function (sdp) { - self.logger.log(sdp); - return pc.setLocalDescription(sdp); - }).catch(function localDescError(e) { - self.emit('peerConnection-SetLocalDescriptionFailed', e); - throw e; - }).then(function onSetLocalDescriptionSuccess() { - return self.waitForIceGatheringComplete(); - }).then(function readySuccess() { - var localDescription = self.peerConnection.localDescription; - return SIP.Utils.reducePromises(modifiers, localDescription); - }).then(function (localDescription) { - self.emit('getDescription', localDescription); - return localDescription.sdp; - }).catch(function createOfferOrAnswerError(e) { - self.logger.error(e); - // TODO: Not sure if this is correct - throw new SIP.Exceptions.GetDescriptionError(e); - }); - } }, - - addDefaultIceCheckingTimeout: { writable: true, value: function addDefaultIceCheckingTimeout(peerConnectionOptions) { - if (peerConnectionOptions.iceCheckingTimeout === undefined) { - peerConnectionOptions.iceCheckingTimeout = 5000; - } - return peerConnectionOptions; - } }, - - addDefaultIceServers: { writable: true, value: function addDefaultIceServers(rtcConfiguration) { - if (!rtcConfiguration.iceServers) { - rtcConfiguration.iceServers = [{ urls: 'stun:stun.l.google.com:19302' }]; - } - return rtcConfiguration; - } }, - - checkAndDefaultConstraints: { writable: true, value: function checkAndDefaultConstraints(constraints) { - var defaultConstraints = { audio: true, video: true }; - constraints = constraints || defaultConstraints; - // Empty object check - if (Object.keys(constraints).length === 0 && constraints.constructor === Object) { - return defaultConstraints; - } - return constraints; - } }, - - initPeerConnection: { writable: true, value: function initPeerConnection(options) { - var self = this; - options = options || {}; - options = this.addDefaultIceCheckingTimeout(options); - options.rtcConfiguration = options.rtcConfiguration || {}; - options.rtcConfiguration = this.addDefaultIceServers(options.rtcConfiguration); - - this.logger.log('initPeerConnection'); - - if (this.peerConnection) { - this.logger.log('Already have a peer connection for this session. Tearing down.'); - this.resetIceGatheringComplete(); - this.peerConnection.close(); - } - - this.peerConnection = new this.WebRTC.RTCPeerConnection(options.rtcConfiguration); - - this.logger.log('New peer connection created'); - this.session.emit('peerConnection-created', this.peerConnection); - - this.peerConnection.ontrack = function (e) { - self.logger.log('track added'); - self.emit('addTrack', e); - }; - - this.peerConnection.onaddstream = function (e) { - self.logger.warn('Using deprecated stream API'); - self.logger.log('stream added'); - self.emit('addStream', e); - }; - - // TODO: There is no remove track listener - this.peerConnection.onremovestream = function (e) { - self.logger.log('stream removed: ' + e.stream.id); - }; - - this.peerConnection.onicecandidate = function (e) { - self.emit('iceCandidate', e); - if (e.candidate) { - self.logger.log('ICE candidate received: ' + (e.candidate.candidate === null ? null : e.candidate.candidate.trim())); - } - }; - - this.peerConnection.onicegatheringstatechange = function () { - self.logger.log('RTCIceGatheringState changed: ' + this.iceGatheringState); - switch (this.iceGatheringState) { - case 'gathering': - self.emit('iceGathering', this); - if (!self.iceGatheringTimer && options.iceCheckingTimeout) { - self.iceGatheringTimeout = false; - self.iceGatheringTimer = SIP.Timers.setTimeout(function () { - self.logger.log('RTCIceChecking Timeout Triggered after ' + options.iceCheckingTimeout + ' milliseconds'); - self.iceGatheringTimeout = true; - self.triggerIceGatheringComplete(); - }, options.iceCheckingTimeout); - } - break; - case 'complete': - self.triggerIceGatheringComplete(); - break; - } - }; - - this.peerConnection.oniceconnectionstatechange = function () { - //need e for commented out case - var stateEvent; - - switch (this.iceConnectionState) { - case 'new': - stateEvent = 'iceConnection'; - break; - case 'checking': - stateEvent = 'iceConnectionChecking'; - break; - case 'connected': - stateEvent = 'iceConnectionConnected'; - break; - case 'completed': - stateEvent = 'iceConnectionCompleted'; - break; - case 'failed': - stateEvent = 'iceConnectionFailed'; - break; - case 'disconnected': - stateEvent = 'iceConnectionDisconnected'; - break; - case 'closed': - stateEvent = 'iceConnectionClosed'; - break; - default: - self.logger.warn('Unknown iceConnection state:', this.iceConnectionState); - return; - } - self.emit(stateEvent, this); - }; - } }, - - acquire: { writable: true, value: function acquire(constraints) { - // Default audio & video to true - constraints = this.checkAndDefaultConstraints(constraints); - - return new SIP.Utils.Promise(function (resolve, reject) { - /* - * Make the call asynchronous, so that ICCs have a chance - * to define callbacks to `userMediaRequest` - */ - this.emit('userMediaRequest', constraints); - - var emitThenCall = function (eventName, callback) { - var callbackArgs = Array.prototype.slice.call(arguments, 2); - // Emit with all of the arguments from the real callback. - var newArgs = [eventName].concat(callbackArgs); - this.emit.apply(this, newArgs); - return callback.apply(null, callbackArgs); - }.bind(this); - - if (constraints.audio || constraints.video) { - this.WebRTC.getUserMedia(constraints).then(emitThenCall.bind(this, 'userMedia', function (streams) { - resolve(streams); - }), emitThenCall.bind(this, 'userMediaFailed', function (e) { - reject(e); - throw e; - })); - } else { - // Local streams were explicitly excluded. - resolve([]); - } - }.bind(this)); - } }, - - isVideoHold: { writable: true, value: function isVideoHold(description) { - if (description.search(/^(m=video.*?)[\s\S]*^(a=sendonly?)/gm) !== -1) { - return true; - } - return false; - } }, - - hasOffer: { writable: true, value: function hasOffer(where) { - var offerState = 'have-' + where + '-offer'; - return this.peerConnection.signalingState === offerState; - } }, - - // ICE gathering state handling - - isIceGatheringComplete: { writable: true, value: function isIceGatheringComplete() { - return this.peerConnection.iceGatheringState === 'complete' || this.iceGatheringTimeout; - } }, - - resetIceGatheringComplete: { writable: true, value: function rejectIceGatheringComplete() { - this.iceGatheringTimeout = false; - - if (this.iceGatheringTimer) { - SIP.Timers.clearTimeout(this.iceGatheringTimer); - this.iceGatheringTimer = null; - } - - if (this.iceGatheringDeferred) { - this.iceGatheringDeferred.reject(); - this.iceGatheringDeferred = null; - } - } }, - - triggerIceGatheringComplete: { writable: true, value: function triggerIceGatheringComplete() { - if (this.isIceGatheringComplete()) { - this.emit('iceGatheringComplete', this); - - if (this.iceGatheringTimer) { - SIP.Timers.clearTimeout(this.iceGatheringTimer); - this.iceGatheringTimer = null; - } - - if (this.iceGatheringDeferred) { - this.iceGatheringDeferred.resolve(); - this.iceGatheringDeferred = null; - } - } - } }, - - waitForIceGatheringComplete: { writable: true, value: function waitForIceGatheringComplete() { - if (this.isIceGatheringComplete()) { - return SIP.Utils.Promise.resolve(); - } else if (!this.isIceGatheringDeferred) { - this.iceGatheringDeferred = SIP.Utils.defer(); - } - return this.iceGatheringDeferred.promise; - } } - }); - - return SessionDescriptionHandler; -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - -/***/ }), -/* 28 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview Incoming SIP Message Sanity Check - */ - -/** - * SIP message sanity check. - * @augments SIP - * @function - * @param {SIP.IncomingMessage} message - * @param {SIP.UA} ua - * @param {SIP.Transport} transport - * @returns {Boolean} - */ - -module.exports = function (SIP) { - var sanityCheck, - requests = [], - responses = [], - all = []; - - // Reply - function reply(status_code, message, transport) { - var to, - response = SIP.Utils.buildStatusLine(status_code), - vias = message.getHeaders('via'), - length = vias.length, - idx = 0; - - for (idx; idx < length; idx++) { - response += "Via: " + vias[idx] + "\r\n"; - } - - to = message.getHeader('To'); - - if (!message.to_tag) { - to += ';tag=' + SIP.Utils.newTag(); - } - - response += "To: " + to + "\r\n"; - response += "From: " + message.getHeader('From') + "\r\n"; - response += "Call-ID: " + message.call_id + "\r\n"; - response += "CSeq: " + message.cseq + " " + message.method + "\r\n"; - response += "\r\n"; - - transport.send(response); - } - - /* - * Sanity Check for incoming Messages - * - * Requests: - * - _rfc3261_8_2_2_1_ Receive a Request with a non supported URI scheme - * - _rfc3261_16_3_4_ Receive a Request already sent by us - * Does not look at via sent-by but at sipjsId, which is inserted as - * a prefix in all initial requests generated by the ua - * - _rfc3261_18_3_request_ Body Content-Length - * - _rfc3261_8_2_2_2_ Merged Requests - * - * Responses: - * - _rfc3261_8_1_3_3_ Multiple Via headers - * - _rfc3261_18_1_2_ sent-by mismatch - * - _rfc3261_18_3_response_ Body Content-Length - * - * All: - * - Minimum headers in a SIP message - */ - - // Sanity Check functions for requests - function rfc3261_8_2_2_1(message, ua, transport) { - if (!message.ruri || message.ruri.scheme !== 'sip') { - reply(416, message, transport); - return false; - } - } - - function rfc3261_16_3_4(message, ua, transport) { - if (!message.to_tag) { - if (message.call_id.substr(0, 5) === ua.configuration.sipjsId) { - reply(482, message, transport); - return false; - } - } - } - - function rfc3261_18_3_request(message, ua, transport) { - var len = SIP.Utils.str_utf8_length(message.body), - contentLength = message.getHeader('content-length'); - - if (len < contentLength) { - reply(400, message, transport); - return false; - } - } - - function rfc3261_8_2_2_2(message, ua, transport) { - var tr, - idx, - fromTag = message.from_tag, - call_id = message.call_id, - cseq = message.cseq; - - if (!message.to_tag) { - if (message.method === SIP.C.INVITE) { - tr = ua.transactions.ist[message.via_branch]; - if (tr) { - return; - } else { - for (idx in ua.transactions.ist) { - tr = ua.transactions.ist[idx]; - if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) { - reply(482, message, transport); - return false; - } - } - } - } else { - tr = ua.transactions.nist[message.via_branch]; - if (tr) { - return; - } else { - for (idx in ua.transactions.nist) { - tr = ua.transactions.nist[idx]; - if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) { - reply(482, message, transport); - return false; - } - } - } - } - } - } - - // Sanity Check functions for responses - function rfc3261_8_1_3_3(message, ua) { - if (message.getHeaders('via').length > 1) { - ua.getLogger('sip.sanitycheck').warn('More than one Via header field present in the response. Dropping the response'); - return false; - } - } - - function rfc3261_18_1_2(message, ua) { - var viaHost = ua.configuration.viaHost; - if (message.via.host !== viaHost || message.via.port !== undefined) { - ua.getLogger('sip.sanitycheck').warn('Via sent-by in the response does not match UA Via host value. Dropping the response'); - return false; - } - } - - function rfc3261_18_3_response(message, ua) { - var len = SIP.Utils.str_utf8_length(message.body), - contentLength = message.getHeader('content-length'); - - if (len < contentLength) { - ua.getLogger('sip.sanitycheck').warn('Message body length is lower than the value in Content-Length header field. Dropping the response'); - return false; - } - } - - // Sanity Check functions for requests and responses - function minimumHeaders(message, ua) { - var mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via'], - idx = mandatoryHeaders.length; - - while (idx--) { - if (!message.hasHeader(mandatoryHeaders[idx])) { - ua.getLogger('sip.sanitycheck').warn('Missing mandatory header field : ' + mandatoryHeaders[idx] + '. Dropping the response'); - return false; - } - } - } - - requests.push(rfc3261_8_2_2_1); - requests.push(rfc3261_16_3_4); - requests.push(rfc3261_18_3_request); - requests.push(rfc3261_8_2_2_2); - - responses.push(rfc3261_8_1_3_3); - responses.push(rfc3261_18_1_2); - responses.push(rfc3261_18_3_response); - - all.push(minimumHeaders); - - sanityCheck = function sanityCheck(message, ua, transport) { - var len, pass; - - len = all.length; - while (len--) { - pass = all[len](message, ua, transport); - if (pass === false) { - return false; - } - } - - if (message instanceof SIP.IncomingRequest) { - len = requests.length; - while (len--) { - pass = requests[len](message, ua, transport); - if (pass === false) { - return false; - } - } - } else if (message instanceof SIP.IncomingResponse) { - len = responses.length; - while (len--) { - pass = responses[len](message, ua, transport); - if (pass === false) { - return false; - } - } - } - - //Everything is OK - return true; - }; - - SIP.sanityCheck = sanityCheck; -}; - -/***/ }), -/* 29 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * @fileoverview SIP Digest Authentication - */ - -/** - * SIP Digest Authentication. - * @augments SIP. - * @function Digest Authentication - * @param {SIP.UA} ua - */ - -module.exports = function (Utils) { - var DigestAuthentication; - - DigestAuthentication = function DigestAuthentication(ua) { - this.logger = ua.getLogger('sipjs.digestauthentication'); - this.username = ua.configuration.authorizationUser; - this.password = ua.configuration.password; - this.cnonce = null; - this.nc = 0; - this.ncHex = '00000000'; - this.response = null; - }; - - /** - * Performs Digest authentication given a SIP request and the challenge - * received in a response to that request. - * Returns true if credentials were successfully generated, false otherwise. - * - * @param {SIP.OutgoingRequest} request - * @param {Object} challenge - */ - DigestAuthentication.prototype.authenticate = function (request, challenge) { - // Inspect and validate the challenge. - - this.algorithm = challenge.algorithm; - this.realm = challenge.realm; - this.nonce = challenge.nonce; - this.opaque = challenge.opaque; - this.stale = challenge.stale; - - if (this.algorithm) { - if (this.algorithm !== 'MD5') { - this.logger.warn('challenge with Digest algorithm different than "MD5", authentication aborted'); - return false; - } - } else { - this.algorithm = 'MD5'; - } - - if (!this.realm) { - this.logger.warn('challenge without Digest realm, authentication aborted'); - return false; - } - - if (!this.nonce) { - this.logger.warn('challenge without Digest nonce, authentication aborted'); - return false; - } - - // 'qop' can contain a list of values (Array). Let's choose just one. - if (challenge.qop) { - if (challenge.qop.indexOf('auth') > -1) { - this.qop = 'auth'; - } else if (challenge.qop.indexOf('auth-int') > -1) { - this.qop = 'auth-int'; - } else { - // Otherwise 'qop' is present but does not contain 'auth' or 'auth-int', so abort here. - this.logger.warn('challenge without Digest qop different than "auth" or "auth-int", authentication aborted'); - return false; - } - } else { - this.qop = null; - } - - // Fill other attributes. - - this.method = request.method; - this.uri = request.ruri; - this.cnonce = Utils.createRandomToken(12); - this.nc += 1; - this.updateNcHex(); - - // nc-value = 8LHEX. Max value = 'FFFFFFFF'. - if (this.nc === 4294967296) { - this.nc = 1; - this.ncHex = '00000001'; - } - - // Calculate the Digest "response" value. - this.calculateResponse(); - - return true; - }; - - /** - * Generate Digest 'response' value. - * @private - */ - DigestAuthentication.prototype.calculateResponse = function () { - var ha1, ha2; - - // HA1 = MD5(A1) = MD5(username:realm:password) - ha1 = Utils.calculateMD5(this.username + ":" + this.realm + ":" + this.password); - - if (this.qop === 'auth') { - // HA2 = MD5(A2) = MD5(method:digestURI) - ha2 = Utils.calculateMD5(this.method + ":" + this.uri); - // response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2) - this.response = Utils.calculateMD5(ha1 + ":" + this.nonce + ":" + this.ncHex + ":" + this.cnonce + ":auth:" + ha2); - } else if (this.qop === 'auth-int') { - // HA2 = MD5(A2) = MD5(method:digestURI:MD5(entityBody)) - ha2 = Utils.calculateMD5(this.method + ":" + this.uri + ":" + Utils.calculateMD5(this.body ? this.body : "")); - // response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2) - this.response = Utils.calculateMD5(ha1 + ":" + this.nonce + ":" + this.ncHex + ":" + this.cnonce + ":auth-int:" + ha2); - } else if (this.qop === null) { - // HA2 = MD5(A2) = MD5(method:digestURI) - ha2 = Utils.calculateMD5(this.method + ":" + this.uri); - // response = MD5(HA1:nonce:HA2) - this.response = Utils.calculateMD5(ha1 + ":" + this.nonce + ":" + ha2); - } - }; - - /** - * Return the Proxy-Authorization or WWW-Authorization header value. - */ - DigestAuthentication.prototype.toString = function () { - var auth_params = []; - - if (!this.response) { - throw new Error('response field does not exist, cannot generate Authorization header'); - } - - auth_params.push('algorithm=' + this.algorithm); - auth_params.push('username="' + this.username + '"'); - auth_params.push('realm="' + this.realm + '"'); - auth_params.push('nonce="' + this.nonce + '"'); - auth_params.push('uri="' + this.uri + '"'); - auth_params.push('response="' + this.response + '"'); - if (this.opaque) { - auth_params.push('opaque="' + this.opaque + '"'); - } - if (this.qop) { - auth_params.push('qop=' + this.qop); - auth_params.push('cnonce="' + this.cnonce + '"'); - auth_params.push('nc=' + this.ncHex); - } - - return 'Digest ' + auth_params.join(', '); - }; - - /** - * Generate the 'nc' value as required by Digest in this.ncHex by reading this.nc. - * @private - */ - DigestAuthentication.prototype.updateNcHex = function () { - var hex = Number(this.nc).toString(16); - this.ncHex = '00000000'.substr(0, 8 - hex.length) + hex; - }; - - return DigestAuthentication; -}; - -/***/ }), -/* 30 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var Grammar = __webpack_require__(31); - -module.exports = function (SIP) { - - return { - parse: function parseCustom(input, startRule) { - var options = { startRule: startRule, SIP: SIP }; - try { - Grammar.parse(input, options); - } catch (e) { - options.data = -1; - } - return options.data; - } - }; -}; - -/***/ }), -/* 31 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* - * Generated by PEG.js 0.10.0. - * - * http://pegjs.org/ - */ - - - -function peg$subclass(child, parent) { - function ctor() { this.constructor = child; } - ctor.prototype = parent.prototype; - child.prototype = new ctor(); -} - -function peg$SyntaxError(message, expected, found, location) { - this.message = message; - this.expected = expected; - this.found = found; - this.location = location; - this.name = "SyntaxError"; - - if (typeof Error.captureStackTrace === "function") { - Error.captureStackTrace(this, peg$SyntaxError); - } -} - -peg$subclass(peg$SyntaxError, Error); - -peg$SyntaxError.buildMessage = function(expected, found) { - var DESCRIBE_EXPECTATION_FNS = { - literal: function(expectation) { - return "\"" + literalEscape(expectation.text) + "\""; - }, - - "class": function(expectation) { - var escapedParts = "", - i; - - for (i = 0; i < expectation.parts.length; i++) { - escapedParts += expectation.parts[i] instanceof Array - ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1]) - : classEscape(expectation.parts[i]); - } - - return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]"; - }, - - any: function(expectation) { - return "any character"; - }, - - end: function(expectation) { - return "end of input"; - }, - - other: function(expectation) { - return expectation.description; - } - }; - - function hex(ch) { - return ch.charCodeAt(0).toString(16).toUpperCase(); - } - - function literalEscape(s) { - return s - .replace(/\\/g, '\\\\') - .replace(/"/g, '\\"') - .replace(/\0/g, '\\0') - .replace(/\t/g, '\\t') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) - .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); - } - - function classEscape(s) { - return s - .replace(/\\/g, '\\\\') - .replace(/\]/g, '\\]') - .replace(/\^/g, '\\^') - .replace(/-/g, '\\-') - .replace(/\0/g, '\\0') - .replace(/\t/g, '\\t') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) - .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); - } - - function describeExpectation(expectation) { - return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); - } - - function describeExpected(expected) { - var descriptions = new Array(expected.length), - i, j; - - for (i = 0; i < expected.length; i++) { - descriptions[i] = describeExpectation(expected[i]); - } - - descriptions.sort(); - - if (descriptions.length > 0) { - for (i = 1, j = 1; i < descriptions.length; i++) { - if (descriptions[i - 1] !== descriptions[i]) { - descriptions[j] = descriptions[i]; - j++; - } - } - descriptions.length = j; - } - - switch (descriptions.length) { - case 1: - return descriptions[0]; - - case 2: - return descriptions[0] + " or " + descriptions[1]; - - default: - return descriptions.slice(0, -1).join(", ") - + ", or " - + descriptions[descriptions.length - 1]; - } - } - - function describeFound(found) { - return found ? "\"" + literalEscape(found) + "\"" : "end of input"; - } - - return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; -}; - -function peg$parse(input, options) { - options = options !== void 0 ? options : {}; - - var peg$FAILED = {}, - - peg$startRuleIndices = { Contact: 118, Name_Addr_Header: 155, Record_Route: 175, Request_Response: 81, SIP_URI: 45, Subscription_State: 185, Supported: 190, Require: 181, Via: 193, absoluteURI: 84, Call_ID: 117, Content_Disposition: 129, Content_Length: 134, Content_Type: 135, CSeq: 145, displayName: 121, Event: 148, From: 150, host: 52, Max_Forwards: 153, Min_SE: 212, Proxy_Authenticate: 156, quoted_string: 40, Refer_To: 177, Replaces: 178, Session_Expires: 209, stun_URI: 216, To: 191, turn_URI: 222, uuid: 225, WWW_Authenticate: 208, challenge: 157, sipfrag: 229, Referred_By: 230 }, - peg$startRuleIndex = 118, - - peg$consts = [ - "\r\n", - peg$literalExpectation("\r\n", false), - /^[0-9]/, - peg$classExpectation([["0", "9"]], false, false), - /^[a-zA-Z]/, - peg$classExpectation([["a", "z"], ["A", "Z"]], false, false), - /^[0-9a-fA-F]/, - peg$classExpectation([["0", "9"], ["a", "f"], ["A", "F"]], false, false), - /^[\0-\xFF]/, - peg$classExpectation([["\0", "\xFF"]], false, false), - /^["]/, - peg$classExpectation(["\""], false, false), - " ", - peg$literalExpectation(" ", false), - "\t", - peg$literalExpectation("\t", false), - /^[a-zA-Z0-9]/, - peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false), - ";", - peg$literalExpectation(";", false), - "/", - peg$literalExpectation("/", false), - "?", - peg$literalExpectation("?", false), - ":", - peg$literalExpectation(":", false), - "@", - peg$literalExpectation("@", false), - "&", - peg$literalExpectation("&", false), - "=", - peg$literalExpectation("=", false), - "+", - peg$literalExpectation("+", false), - "$", - peg$literalExpectation("$", false), - ",", - peg$literalExpectation(",", false), - "-", - peg$literalExpectation("-", false), - "_", - peg$literalExpectation("_", false), - ".", - peg$literalExpectation(".", false), - "!", - peg$literalExpectation("!", false), - "~", - peg$literalExpectation("~", false), - "*", - peg$literalExpectation("*", false), - "'", - peg$literalExpectation("'", false), - "(", - peg$literalExpectation("(", false), - ")", - peg$literalExpectation(")", false), - "%", - peg$literalExpectation("%", false), - function() {return " "; }, - function() {return ':'; }, - /^[!-~]/, - peg$classExpectation([["!", "~"]], false, false), - /^[\x80-\uFFFF]/, - peg$classExpectation([["\x80", "\uFFFF"]], false, false), - /^[\x80-\xBF]/, - peg$classExpectation([["\x80", "\xBF"]], false, false), - /^[a-f]/, - peg$classExpectation([["a", "f"]], false, false), - "`", - peg$literalExpectation("`", false), - "<", - peg$literalExpectation("<", false), - ">", - peg$literalExpectation(">", false), - "\\", - peg$literalExpectation("\\", false), - "[", - peg$literalExpectation("[", false), - "]", - peg$literalExpectation("]", false), - "{", - peg$literalExpectation("{", false), - "}", - peg$literalExpectation("}", false), - function() {return "*"; }, - function() {return "/"; }, - function() {return "="; }, - function() {return "("; }, - function() {return ")"; }, - function() {return ">"; }, - function() {return "<"; }, - function() {return ","; }, - function() {return ";"; }, - function() {return ":"; }, - function() {return "\""; }, - /^[!-']/, - peg$classExpectation([["!", "'"]], false, false), - /^[*-[]/, - peg$classExpectation([["*", "["]], false, false), - /^[\]-~]/, - peg$classExpectation([["]", "~"]], false, false), - function(contents) { - return contents; }, - /^[#-[]/, - peg$classExpectation([["#", "["]], false, false), - /^[\0-\t]/, - peg$classExpectation([["\0", "\t"]], false, false), - /^[\x0B-\f]/, - peg$classExpectation([["\x0B", "\f"]], false, false), - /^[\x0E-\x7F]/, - peg$classExpectation([["\x0E", "\x7F"]], false, false), - function() { - options.data.uri = new options.SIP.URI(options.data.scheme, options.data.user, options.data.host, options.data.port); - delete options.data.scheme; - delete options.data.user; - delete options.data.host; - delete options.data.host_type; - delete options.data.port; - }, - function() { - options.data.uri = new options.SIP.URI(options.data.scheme, options.data.user, options.data.host, options.data.port, options.data.uri_params, options.data.uri_headers); - delete options.data.scheme; - delete options.data.user; - delete options.data.host; - delete options.data.host_type; - delete options.data.port; - delete options.data.uri_params; - - if (options.startRule === 'SIP_URI') { options.data = options.data.uri;} - }, - "sips", - peg$literalExpectation("sips", true), - "sip", - peg$literalExpectation("sip", true), - function(uri_scheme) { - options.data.scheme = uri_scheme; }, - function() { - options.data.user = decodeURIComponent(text().slice(0, -1));}, - function() { - options.data.password = text(); }, - function() { - options.data.host = text(); - return options.data.host; }, - function() { - options.data.host_type = 'domain'; - return text(); }, - /^[a-zA-Z0-9_\-]/, - peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "_", "-"], false, false), - /^[a-zA-Z0-9\-]/, - peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "-"], false, false), - function() { - options.data.host_type = 'IPv6'; - return text(); }, - "::", - peg$literalExpectation("::", false), - function() { - options.data.host_type = 'IPv6'; - return text(); }, - function() { - options.data.host_type = 'IPv4'; - return text(); }, - "25", - peg$literalExpectation("25", false), - /^[0-5]/, - peg$classExpectation([["0", "5"]], false, false), - "2", - peg$literalExpectation("2", false), - /^[0-4]/, - peg$classExpectation([["0", "4"]], false, false), - "1", - peg$literalExpectation("1", false), - /^[1-9]/, - peg$classExpectation([["1", "9"]], false, false), - function(port) { - port = parseInt(port.join('')); - options.data.port = port; - return port; }, - "transport=", - peg$literalExpectation("transport=", true), - "udp", - peg$literalExpectation("udp", true), - "tcp", - peg$literalExpectation("tcp", true), - "sctp", - peg$literalExpectation("sctp", true), - "tls", - peg$literalExpectation("tls", true), - function(transport) { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['transport'] = transport.toLowerCase(); }, - "user=", - peg$literalExpectation("user=", true), - "phone", - peg$literalExpectation("phone", true), - "ip", - peg$literalExpectation("ip", true), - function(user) { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['user'] = user.toLowerCase(); }, - "method=", - peg$literalExpectation("method=", true), - function(method) { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['method'] = method; }, - "ttl=", - peg$literalExpectation("ttl=", true), - function(ttl) { - if(!options.data.params) options.data.params={}; - options.data.params['ttl'] = ttl; }, - "maddr=", - peg$literalExpectation("maddr=", true), - function(maddr) { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['maddr'] = maddr; }, - "lr", - peg$literalExpectation("lr", true), - function() { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['lr'] = undefined; }, - function(param, value) { - if(!options.data.uri_params) options.data.uri_params = {}; - if (value === null){ - value = undefined; - } - else { - value = value[1]; - } - options.data.uri_params[param.toLowerCase()] = value && value.toLowerCase();}, - function(hname, hvalue) { - hname = hname.join('').toLowerCase(); - hvalue = hvalue.join(''); - if(!options.data.uri_headers) options.data.uri_headers = {}; - if (!options.data.uri_headers[hname]) { - options.data.uri_headers[hname] = [hvalue]; - } else { - options.data.uri_headers[hname].push(hvalue); - }}, - function() { - // lots of tests fail if this isn't guarded... - if (options.startRule === 'Refer_To') { - options.data.uri = new options.SIP.URI(options.data.scheme, options.data.user, options.data.host, options.data.port, options.data.uri_params, options.data.uri_headers); - delete options.data.scheme; - delete options.data.user; - delete options.data.host; - delete options.data.host_type; - delete options.data.port; - delete options.data.uri_params; - } - }, - "//", - peg$literalExpectation("//", false), - function() { - options.data.scheme= text(); }, - peg$literalExpectation("SIP", true), - function() { - options.data.sip_version = text(); }, - "INVITE", - peg$literalExpectation("INVITE", false), - "ACK", - peg$literalExpectation("ACK", false), - "VXACH", - peg$literalExpectation("VXACH", false), - "OPTIONS", - peg$literalExpectation("OPTIONS", false), - "BYE", - peg$literalExpectation("BYE", false), - "CANCEL", - peg$literalExpectation("CANCEL", false), - "REGISTER", - peg$literalExpectation("REGISTER", false), - "SUBSCRIBE", - peg$literalExpectation("SUBSCRIBE", false), - "NOTIFY", - peg$literalExpectation("NOTIFY", false), - "REFER", - peg$literalExpectation("REFER", false), - function() { - - options.data.method = text(); - return options.data.method; }, - function(status_code) { - options.data.status_code = parseInt(status_code.join('')); }, - function() { - options.data.reason_phrase = text(); }, - function() { - options.data = text(); }, - function() { - var idx, length; - length = options.data.multi_header.length; - for (idx = 0; idx < length; idx++) { - if (options.data.multi_header[idx].parsed === null) { - options.data = null; - break; - } - } - if (options.data !== null) { - options.data = options.data.multi_header; - } else { - options.data = -1; - }}, - function() { - var header; - if(!options.data.multi_header) options.data.multi_header = []; - try { - header = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - delete options.data.uri; - delete options.data.displayName; - delete options.data.params; - } catch(e) { - header = null; - } - options.data.multi_header.push( { 'position': peg$currPos, - 'offset': location().start.offset, - 'parsed': header - });}, - function(displayName) { - displayName = text().trim(); - if (displayName[0] === '\"') { - displayName = displayName.substring(1, displayName.length-1); - } - options.data.displayName = displayName; }, - "q", - peg$literalExpectation("q", true), - function(q) { - if(!options.data.params) options.data.params = {}; - options.data.params['q'] = q; }, - "expires", - peg$literalExpectation("expires", true), - function(expires) { - if(!options.data.params) options.data.params = {}; - options.data.params['expires'] = expires; }, - function(delta_seconds) { - return parseInt(delta_seconds.join('')); }, - "0", - peg$literalExpectation("0", false), - function() { - return parseFloat(text()); }, - function(param, value) { - if(!options.data.params) options.data.params = {}; - if (value === null){ - value = undefined; - } - else { - value = value[1]; - } - options.data.params[param.toLowerCase()] = value;}, - "render", - peg$literalExpectation("render", true), - "session", - peg$literalExpectation("session", true), - "icon", - peg$literalExpectation("icon", true), - "alert", - peg$literalExpectation("alert", true), - function() { - if (options.startRule === 'Content_Disposition') { - options.data.type = text().toLowerCase(); - } - }, - "handling", - peg$literalExpectation("handling", true), - "optional", - peg$literalExpectation("optional", true), - "required", - peg$literalExpectation("required", true), - function(length) { - options.data = parseInt(length.join('')); }, - function() { - options.data = text(); }, - "text", - peg$literalExpectation("text", true), - "image", - peg$literalExpectation("image", true), - "audio", - peg$literalExpectation("audio", true), - "video", - peg$literalExpectation("video", true), - "application", - peg$literalExpectation("application", true), - "message", - peg$literalExpectation("message", true), - "multipart", - peg$literalExpectation("multipart", true), - "x-", - peg$literalExpectation("x-", true), - function(cseq_value) { - options.data.value=parseInt(cseq_value.join('')); }, - function(expires) {options.data = expires; }, - function(event_type) { - options.data.event = event_type.toLowerCase(); }, - function() { - var tag = options.data.tag; - options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - if (tag) {options.data.setParam('tag',tag)} - }, - "tag", - peg$literalExpectation("tag", true), - function(tag) {options.data.tag = tag; }, - function(forwards) { - options.data = parseInt(forwards.join('')); }, - function(min_expires) {options.data = min_expires; }, - function() { - options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - }, - "digest", - peg$literalExpectation("Digest", true), - "realm", - peg$literalExpectation("realm", true), - function(realm) { options.data.realm = realm; }, - "domain", - peg$literalExpectation("domain", true), - "nonce", - peg$literalExpectation("nonce", true), - function(nonce) { options.data.nonce=nonce; }, - "opaque", - peg$literalExpectation("opaque", true), - function(opaque) { options.data.opaque=opaque; }, - "stale", - peg$literalExpectation("stale", true), - "true", - peg$literalExpectation("true", true), - function() { options.data.stale=true; }, - "false", - peg$literalExpectation("false", true), - function() { options.data.stale=false; }, - "algorithm", - peg$literalExpectation("algorithm", true), - "md5", - peg$literalExpectation("MD5", true), - "md5-sess", - peg$literalExpectation("MD5-sess", true), - function(algorithm) { - options.data.algorithm=algorithm.toUpperCase(); }, - "qop", - peg$literalExpectation("qop", true), - "auth-int", - peg$literalExpectation("auth-int", true), - "auth", - peg$literalExpectation("auth", true), - function(qop_value) { - options.data.qop || (options.data.qop=[]); - options.data.qop.push(qop_value.toLowerCase()); }, - function(rack_value) { - options.data.value=parseInt(rack_value.join('')); }, - function() { - var idx, length; - length = options.data.multi_header.length; - for (idx = 0; idx < length; idx++) { - if (options.data.multi_header[idx].parsed === null) { - options.data = null; - break; - } - } - if (options.data !== null) { - options.data = options.data.multi_header; - } else { - options.data = -1; - }}, - function() { - var header; - if(!options.data.multi_header) options.data.multi_header = []; - try { - header = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - delete options.data.uri; - delete options.data.displayName; - delete options.data.params; - } catch(e) { - header = null; - } - options.data.multi_header.push( { 'position': peg$currPos, - 'offset': location().start.offset, - 'parsed': header - });}, - function() { - options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - }, - function() { - if (!(options.data.replaces_from_tag && options.data.replaces_to_tag)) { - options.data = -1; - } - }, - function() { - options.data = { - call_id: options.data - }; - }, - "from-tag", - peg$literalExpectation("from-tag", true), - function(from_tag) { - options.data.replaces_from_tag = from_tag; - }, - "to-tag", - peg$literalExpectation("to-tag", true), - function(to_tag) { - options.data.replaces_to_tag = to_tag; - }, - "early-only", - peg$literalExpectation("early-only", true), - function() { - options.data.early_only = true; - }, - function(head, r) {return r;}, - function(head, tail) { return list(head, tail); }, - function(value) { - if (options.startRule === 'Require') { - options.data = value || []; - } - }, - function(rseq_value) { - options.data.value=parseInt(rseq_value.join('')); }, - "active", - peg$literalExpectation("active", true), - "pending", - peg$literalExpectation("pending", true), - "terminated", - peg$literalExpectation("terminated", true), - function() { - options.data.state = text(); }, - "reason", - peg$literalExpectation("reason", true), - function(reason) { - if (typeof reason !== 'undefined') options.data.reason = reason; }, - function(expires) { - if (typeof expires !== 'undefined') options.data.expires = expires; }, - "retry_after", - peg$literalExpectation("retry_after", true), - function(retry_after) { - if (typeof retry_after !== 'undefined') options.data.retry_after = retry_after; }, - "deactivated", - peg$literalExpectation("deactivated", true), - "probation", - peg$literalExpectation("probation", true), - "rejected", - peg$literalExpectation("rejected", true), - "timeout", - peg$literalExpectation("timeout", true), - "giveup", - peg$literalExpectation("giveup", true), - "noresource", - peg$literalExpectation("noresource", true), - "invariant", - peg$literalExpectation("invariant", true), - function(value) { - if (options.startRule === 'Supported') { - options.data = value || []; - } - }, - function() { - var tag = options.data.tag; - options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - if (tag) {options.data.setParam('tag',tag)} - }, - "ttl", - peg$literalExpectation("ttl", true), - function(via_ttl_value) { - options.data.ttl = via_ttl_value; }, - "maddr", - peg$literalExpectation("maddr", true), - function(via_maddr) { - options.data.maddr = via_maddr; }, - "received", - peg$literalExpectation("received", true), - function(via_received) { - options.data.received = via_received; }, - "branch", - peg$literalExpectation("branch", true), - function(via_branch) { - options.data.branch = via_branch; }, - "rport", - peg$literalExpectation("rport", true), - function() { - if(typeof response_port !== 'undefined') - options.data.rport = response_port.join(''); }, - function(via_protocol) { - options.data.protocol = via_protocol; }, - peg$literalExpectation("UDP", true), - peg$literalExpectation("TCP", true), - peg$literalExpectation("TLS", true), - peg$literalExpectation("SCTP", true), - function(via_transport) { - options.data.transport = via_transport; }, - function() { - options.data.host = text(); }, - function(via_sent_by_port) { - options.data.port = parseInt(via_sent_by_port.join('')); }, - function(ttl) { - return parseInt(ttl.join('')); }, - function(deltaSeconds) { - if (options.startRule === 'Session_Expires') { - options.data.deltaSeconds = deltaSeconds; - } - }, - "refresher", - peg$literalExpectation("refresher", false), - "uas", - peg$literalExpectation("uas", false), - "uac", - peg$literalExpectation("uac", false), - function(endpoint) { - if (options.startRule === 'Session_Expires') { - options.data.refresher = endpoint; - } - }, - function(deltaSeconds) { - if (options.startRule === 'Min_SE') { - options.data = deltaSeconds; - } - }, - "stuns", - peg$literalExpectation("stuns", true), - "stun", - peg$literalExpectation("stun", true), - function(scheme) { - options.data.scheme = scheme; }, - function(host) { - options.data.host = host; }, - "?transport=", - peg$literalExpectation("?transport=", false), - "turns", - peg$literalExpectation("turns", true), - "turn", - peg$literalExpectation("turn", true), - function() { - options.data.transport = transport; }, - function() { - options.data = text(); }, - "Referred-By", - peg$literalExpectation("Referred-By", false), - "b", - peg$literalExpectation("b", false), - "cid", - peg$literalExpectation("cid", false) - ], - - peg$bytecode = [ - peg$decode("2 \"\"6 7!"), - peg$decode("4\"\"\"5!7#"), - peg$decode("4$\"\"5!7%"), - peg$decode("4&\"\"5!7'"), - peg$decode(";'.# &;("), - peg$decode("4(\"\"5!7)"), - peg$decode("4*\"\"5!7+"), - peg$decode("2,\"\"6,7-"), - peg$decode("2.\"\"6.7/"), - peg$decode("40\"\"5!71"), - peg$decode("22\"\"6273.\x89 &24\"\"6475.} &26\"\"6677.q &28\"\"6879.e &2:\"\"6:7;.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E"), - peg$decode(";).# &;,"), - peg$decode("2F\"\"6F7G.} &2H\"\"6H7I.q &2J\"\"6J7K.e &2L\"\"6L7M.Y &2N\"\"6N7O.M &2P\"\"6P7Q.A &2R\"\"6R7S.5 &2T\"\"6T7U.) &2V\"\"6V7W"), - peg$decode("%%2X\"\"6X7Y/5#;#/,$;#/#$+#)(#'#(\"'#&'#/\"!&,)"), - peg$decode("%%$;$0#*;$&/,#; /#$+\")(\"'#&'#.\" &\"/=#$;$/�#*;$&&&#/'$8\":Z\" )(\"'#&'#"), - peg$decode(";..\" &\""), - peg$decode("%$;'.# &;(0)*;'.# &;(&/?#28\"\"6879/0$;//'$8#:[# )(#'#(\"'#&'#"), - peg$decode("%%$;2/�#*;2&&&#/g#$%$;.0#*;.&/,#;2/#$+\")(\"'#&'#0=*%$;.0#*;.&/,#;2/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/\"!&,)"), - peg$decode("4\\\"\"5!7].# &;3"), - peg$decode("4^\"\"5!7_"), - peg$decode("4`\"\"5!7a"), - peg$decode(";!.) &4b\"\"5!7c"), - peg$decode("%$;).\x95 &2F\"\"6F7G.\x89 &2J\"\"6J7K.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O/\x9E#0\x9B*;).\x95 &2F\"\"6F7G.\x89 &2J\"\"6J7K.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O&&&#/\"!&,)"), - peg$decode("%$;).\x89 &2F\"\"6F7G.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O/\x92#0\x8F*;).\x89 &2F\"\"6F7G.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O&&&#/\"!&,)"), - peg$decode("2T\"\"6T7U.\xE3 &2V\"\"6V7W.\xD7 &2f\"\"6f7g.\xCB &2h\"\"6h7i.\xBF &2:\"\"6:7;.\xB3 &2D\"\"6D7E.\xA7 &22\"\"6273.\x9B &28\"\"6879.\x8F &2j\"\"6j7k.\x83 &;&.} &24\"\"6475.q &2l\"\"6l7m.e &2n\"\"6n7o.Y &26\"\"6677.M &2>\"\"6>7?.A &2p\"\"6p7q.5 &2r\"\"6r7s.) &;'.# &;("), - peg$decode("%$;).\u012B &2F\"\"6F7G.\u011F &2J\"\"6J7K.\u0113 &2L\"\"6L7M.\u0107 &2X\"\"6X7Y.\xFB &2P\"\"6P7Q.\xEF &2H\"\"6H7I.\xE3 &2@\"\"6@7A.\xD7 &2d\"\"6d7e.\xCB &2R\"\"6R7S.\xBF &2N\"\"6N7O.\xB3 &2T\"\"6T7U.\xA7 &2V\"\"6V7W.\x9B &2f\"\"6f7g.\x8F &2h\"\"6h7i.\x83 &28\"\"6879.w &2j\"\"6j7k.k &;&.e &24\"\"6475.Y &2l\"\"6l7m.M &2n\"\"6n7o.A &26\"\"6677.5 &2p\"\"6p7q.) &2r\"\"6r7s/\u0134#0\u0131*;).\u012B &2F\"\"6F7G.\u011F &2J\"\"6J7K.\u0113 &2L\"\"6L7M.\u0107 &2X\"\"6X7Y.\xFB &2P\"\"6P7Q.\xEF &2H\"\"6H7I.\xE3 &2@\"\"6@7A.\xD7 &2d\"\"6d7e.\xCB &2R\"\"6R7S.\xBF &2N\"\"6N7O.\xB3 &2T\"\"6T7U.\xA7 &2V\"\"6V7W.\x9B &2f\"\"6f7g.\x8F &2h\"\"6h7i.\x83 &28\"\"6879.w &2j\"\"6j7k.k &;&.e &24\"\"6475.Y &2l\"\"6l7m.M &2n\"\"6n7o.A &26\"\"6677.5 &2p\"\"6p7q.) &2r\"\"6r7s&&&#/\"!&,)"), - peg$decode("%;//?#2P\"\"6P7Q/0$;//'$8#:t# )(#'#(\"'#&'#"), - peg$decode("%;//?#24\"\"6475/0$;//'$8#:u# )(#'#(\"'#&'#"), - peg$decode("%;//?#2>\"\"6>7?/0$;//'$8#:v# )(#'#(\"'#&'#"), - peg$decode("%;//?#2T\"\"6T7U/0$;//'$8#:w# )(#'#(\"'#&'#"), - peg$decode("%;//?#2V\"\"6V7W/0$;//'$8#:x# )(#'#(\"'#&'#"), - peg$decode("%2h\"\"6h7i/0#;//'$8\":y\" )(\"'#&'#"), - peg$decode("%;//6#2f\"\"6f7g/'$8\":z\" )(\"'#&'#"), - peg$decode("%;//?#2D\"\"6D7E/0$;//'$8#:{# )(#'#(\"'#&'#"), - peg$decode("%;//?#22\"\"6273/0$;//'$8#:|# )(#'#(\"'#&'#"), - peg$decode("%;//?#28\"\"6879/0$;//'$8#:}# )(#'#(\"'#&'#"), - peg$decode("%;//0#;&/'$8\":~\" )(\"'#&'#"), - peg$decode("%;&/0#;//'$8\":~\" )(\"'#&'#"), - peg$decode("%;=/T#$;G.) &;K.# &;F0/*;G.) &;K.# &;F&/,$;>/#$+#)(#'#(\"'#&'#"), - peg$decode("4\x7F\"\"5!7\x80.A &4\x81\"\"5!7\x82.5 &4\x83\"\"5!7\x84.) &;3.# &;."), - peg$decode("%%;//Q#;&/H$$;J.# &;K0)*;J.# &;K&/,$;&/#$+$)($'#(#'#(\"'#&'#/\"!&,)"), - peg$decode("%;//]#;&/T$%$;J.# &;K0)*;J.# &;K&/\"!&,)/1$;&/($8$:\x85$!!)($'#(#'#(\"'#&'#"), - peg$decode(";..G &2L\"\"6L7M.; &4\x86\"\"5!7\x87./ &4\x83\"\"5!7\x84.# &;3"), - peg$decode("%2j\"\"6j7k/J#4\x88\"\"5!7\x89.5 &4\x8A\"\"5!7\x8B.) &4\x8C\"\"5!7\x8D/#$+\")(\"'#&'#"), - peg$decode("%;N/M#28\"\"6879/>$;O.\" &\"/0$;S/'$8$:\x8E$ )($'#(#'#(\"'#&'#"), - peg$decode("%;N/d#28\"\"6879/U$;O.\" &\"/G$;S/>$;_/5$;l.\" &\"/'$8&:\x8F& )(&'#(%'#($'#(#'#(\"'#&'#"), - peg$decode("%3\x90\"\"5$7\x91.) &3\x92\"\"5#7\x93/' 8!:\x94!! )"), - peg$decode("%;P/]#%28\"\"6879/,#;R/#$+\")(\"'#&'#.\" &\"/6$2:\"\"6:7;/'$8#:\x95# )(#'#(\"'#&'#"), - peg$decode("$;+.) &;-.# &;Q/2#0/*;+.) &;-.# &;Q&&&#"), - peg$decode("2<\"\"6<7=.q &2>\"\"6>7?.e &2@\"\"6@7A.Y &2B\"\"6B7C.M &2D\"\"6D7E.A &22\"\"6273.5 &26\"\"6677.) &24\"\"6475"), - peg$decode("%$;+._ &;-.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E0e*;+._ &;-.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E&/& 8!:\x96! )"), - peg$decode("%;T/J#%28\"\"6879/,#;^/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"), - peg$decode("%;U.) &;\\.# &;X/& 8!:\x97! )"), - peg$decode("%$%;V/2#2J\"\"6J7K/#$+\")(\"'#&'#0<*%;V/2#2J\"\"6J7K/#$+\")(\"'#&'#&/D#;W/;$2J\"\"6J7K.\" &\"/'$8#:\x98# )(#'#(\"'#&'#"), - peg$decode("$4\x99\"\"5!7\x9A/,#0)*4\x99\"\"5!7\x9A&&&#"), - peg$decode("%4$\"\"5!7%/?#$4\x9B\"\"5!7\x9C0)*4\x9B\"\"5!7\x9C&/#$+\")(\"'#&'#"), - peg$decode("%2l\"\"6l7m/?#;Y/6$2n\"\"6n7o/'$8#:\x9D# )(#'#(\"'#&'#"), - peg$decode("%%;Z/\xB3#28\"\"6879/\xA4$;Z/\x9B$28\"\"6879/\x8C$;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+-)(-'#(,'#(+'#(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0790 &%2\x9E\"\"6\x9E7\x9F/\xA4#;Z/\x9B$28\"\"6879/\x8C$;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+,)(,'#(+'#(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u06F9 &%2\x9E\"\"6\x9E7\x9F/\x8C#;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+*)(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u067A &%2\x9E\"\"6\x9E7\x9F/t#;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0613 &%2\x9E\"\"6\x9E7\x9F/\\#;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+&)(&'#(%'#($'#(#'#(\"'#&'#.\u05C4 &%2\x9E\"\"6\x9E7\x9F/D#;Z/;$28\"\"6879/,$;[/#$+$)($'#(#'#(\"'#&'#.\u058D &%2\x9E\"\"6\x9E7\x9F/,#;[/#$+\")(\"'#&'#.\u056E &%2\x9E\"\"6\x9E7\x9F/,#;Z/#$+\")(\"'#&'#.\u054F &%;Z/\x9B#2\x9E\"\"6\x9E7\x9F/\x8C$;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$++)(+'#(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u04C7 &%;Z/\xAA#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x83$2\x9E\"\"6\x9E7\x9F/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+*)(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0430 &%;Z/\xB9#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x92$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/k$2\x9E\"\"6\x9E7\x9F/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+))()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u038A &%;Z/\xC8#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xA1$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/z$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/S$2\x9E\"\"6\x9E7\x9F/D$;Z/;$28\"\"6879/,$;[/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u02D5 &%;Z/\xD7#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xB0$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x89$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/b$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/;$2\x9E\"\"6\x9E7\x9F/,$;[/#$+')(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0211 &%;Z/\xFE#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xD7$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xB0$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x89$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/b$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/;$2\x9E\"\"6\x9E7\x9F/,$;Z/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0126 &%;Z/\u011C#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xF5$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xCE$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xA7$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x80$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/Y$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/2$2\x9E\"\"6\x9E7\x9F/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#/& 8!:\xA0! )"), - peg$decode("%;#/M#;#.\" &\"/?$;#.\" &\"/1$;#.\" &\"/#$+$)($'#(#'#(\"'#&'#"), - peg$decode("%;Z/;#28\"\"6879/,$;Z/#$+#)(#'#(\"'#&'#.# &;\\"), - peg$decode("%;]/o#2J\"\"6J7K/`$;]/W$2J\"\"6J7K/H$;]/?$2J\"\"6J7K/0$;]/'$8':\xA1' )(''#(&'#(%'#($'#(#'#(\"'#&'#"), - peg$decode("%2\xA2\"\"6\xA27\xA3/2#4\xA4\"\"5!7\xA5/#$+\")(\"'#&'#.\x98 &%2\xA6\"\"6\xA67\xA7/;#4\xA8\"\"5!7\xA9/,$;!/#$+#)(#'#(\"'#&'#.j &%2\xAA\"\"6\xAA7\xAB/5#;!/,$;!/#$+#)(#'#(\"'#&'#.B &%4\xAC\"\"5!7\xAD/,#;!/#$+\")(\"'#&'#.# &;!"), - peg$decode("%%;!.\" &\"/[#;!.\" &\"/M$;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+%)(%'#($'#(#'#(\"'#&'#/' 8!:\xAE!! )"), - peg$decode("$%22\"\"6273/,#;`/#$+\")(\"'#&'#0<*%22\"\"6273/,#;`/#$+\")(\"'#&'#&"), - peg$decode(";a.A &;b.; &;c.5 &;d./ &;e.) &;f.# &;g"), - peg$decode("%3\xAF\"\"5*7\xB0/a#3\xB1\"\"5#7\xB2.G &3\xB3\"\"5#7\xB4.; &3\xB5\"\"5$7\xB6./ &3\xB7\"\"5#7\xB8.# &;6/($8\":\xB9\"! )(\"'#&'#"), - peg$decode("%3\xBA\"\"5%7\xBB/I#3\xBC\"\"5%7\xBD./ &3\xBE\"\"5\"7\xBF.# &;6/($8\":\xC0\"! )(\"'#&'#"), - peg$decode("%3\xC1\"\"5'7\xC2/1#;\x8F/($8\":\xC3\"! )(\"'#&'#"), - peg$decode("%3\xC4\"\"5$7\xC5/1#;\xEF/($8\":\xC6\"! )(\"'#&'#"), - peg$decode("%3\xC7\"\"5&7\xC8/1#;T/($8\":\xC9\"! )(\"'#&'#"), - peg$decode("%3\xCA\"\"5\"7\xCB/N#%2>\"\"6>7?/,#;6/#$+\")(\"'#&'#.\" &\"/'$8\":\xCC\" )(\"'#&'#"), - peg$decode("%;h/P#%2>\"\"6>7?/,#;i/#$+\")(\"'#&'#.\" &\"/)$8\":\xCD\"\"! )(\"'#&'#"), - peg$decode("%$;j/�#*;j&&&#/\"!&,)"), - peg$decode("%$;j/�#*;j&&&#/\"!&,)"), - peg$decode(";k.) &;+.# &;-"), - peg$decode("2l\"\"6l7m.e &2n\"\"6n7o.Y &24\"\"6475.M &28\"\"6879.A &2<\"\"6<7=.5 &2@\"\"6@7A.) &2B\"\"6B7C"), - peg$decode("%26\"\"6677/n#;m/e$$%2<\"\"6<7=/,#;m/#$+\")(\"'#&'#0<*%2<\"\"6<7=/,#;m/#$+\")(\"'#&'#&/#$+#)(#'#(\"'#&'#"), - peg$decode("%;n/A#2>\"\"6>7?/2$;o/)$8#:\xCE#\"\" )(#'#(\"'#&'#"), - peg$decode("$;p.) &;+.# &;-/2#0/*;p.) &;+.# &;-&&&#"), - peg$decode("$;p.) &;+.# &;-0/*;p.) &;+.# &;-&"), - peg$decode("2l\"\"6l7m.e &2n\"\"6n7o.Y &24\"\"6475.M &26\"\"6677.A &28\"\"6879.5 &2@\"\"6@7A.) &2B\"\"6B7C"), - peg$decode(";\x90.# &;r"), - peg$decode("%;\x8F/G#;'/>$;s/5$;'/,$;\x84/#$+%)(%'#($'#(#'#(\"'#&'#"), - peg$decode(";M.# &;t"), - peg$decode("%;\x7F/E#28\"\"6879/6$;u.# &;x/'$8#:\xCF# )(#'#(\"'#&'#"), - peg$decode("%;v.# &;w/J#%26\"\"6677/,#;\x83/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"), - peg$decode("%2\xD0\"\"6\xD07\xD1/:#;\x80/1$;w.\" &\"/#$+#)(#'#(\"'#&'#"), - peg$decode("%24\"\"6475/,#;{/#$+\")(\"'#&'#"), - peg$decode("%;z/3#$;y0#*;y&/#$+\")(\"'#&'#"), - peg$decode(";*.) &;+.# &;-"), - peg$decode(";+.\x8F &;-.\x89 &22\"\"6273.} &26\"\"6677.q &28\"\"6879.e &2:\"\"6:7;.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E"), - peg$decode("%;|/e#$%24\"\"6475/,#;|/#$+\")(\"'#&'#0<*%24\"\"6475/,#;|/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"), - peg$decode("%$;~0#*;~&/e#$%22\"\"6273/,#;}/#$+\")(\"'#&'#0<*%22\"\"6273/,#;}/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"), - peg$decode("$;~0#*;~&"), - peg$decode(";+.w &;-.q &28\"\"6879.e &2:\"\"6:7;.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E"), - peg$decode("%%;\"/\x87#$;\".G &;!.A &2@\"\"6@7A.5 &2F\"\"6F7G.) &2J\"\"6J7K0M*;\".G &;!.A &2@\"\"6@7A.5 &2F\"\"6F7G.) &2J\"\"6J7K&/#$+\")(\"'#&'#/& 8!:\xD2! )"), - peg$decode(";\x81.# &;\x82"), - peg$decode("%%;O/2#2:\"\"6:7;/#$+\")(\"'#&'#.\" &\"/,#;S/#$+\")(\"'#&'#.\" &\""), - peg$decode("$;+.\x83 &;-.} &2B\"\"6B7C.q &2D\"\"6D7E.e &22\"\"6273.Y &28\"\"6879.M &2:\"\"6:7;.A &2<\"\"6<7=.5 &2>\"\"6>7?.) &2@\"\"6@7A/\x8C#0\x89*;+.\x83 &;-.} &2B\"\"6B7C.q &2D\"\"6D7E.e &22\"\"6273.Y &28\"\"6879.M &2:\"\"6:7;.A &2<\"\"6<7=.5 &2>\"\"6>7?.) &2@\"\"6@7A&&&#"), - peg$decode("$;y0#*;y&"), - peg$decode("%3\x92\"\"5#7\xD3/q#24\"\"6475/b$$;!/�#*;!&&&#/L$2J\"\"6J7K/=$$;!/�#*;!&&&#/'$8%:\xD4% )(%'#($'#(#'#(\"'#&'#"), - peg$decode("2\xD5\"\"6\xD57\xD6"), - peg$decode("2\xD7\"\"6\xD77\xD8"), - peg$decode("2\xD9\"\"6\xD97\xDA"), - peg$decode("2\xDB\"\"6\xDB7\xDC"), - peg$decode("2\xDD\"\"6\xDD7\xDE"), - peg$decode("2\xDF\"\"6\xDF7\xE0"), - peg$decode("2\xE1\"\"6\xE17\xE2"), - peg$decode("2\xE3\"\"6\xE37\xE4"), - peg$decode("2\xE5\"\"6\xE57\xE6"), - peg$decode("2\xE7\"\"6\xE77\xE8"), - peg$decode("%;\x85.S &;\x86.M &;\x88.G &;\x89.A &;\x8A.; &;\x8B.5 &;\x8C./ &;\x8D.) &;\x8E.# &;6/& 8!:\xE9! )"), - peg$decode("%;\x84/G#;'/>$;\x91/5$;'/,$;\x93/#$+%)(%'#($'#(#'#(\"'#&'#"), - peg$decode("%;\x92/' 8!:\xEA!! )"), - peg$decode("%;!/5#;!/,$;!/#$+#)(#'#(\"'#&'#"), - peg$decode("%$;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(0G*;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(&/& 8!:\xEB! )"), - peg$decode("%;\xB5/Y#$%;A/,#;\xB5/#$+\")(\"'#&'#06*%;A/,#;\xB5/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"), - peg$decode("%;9/N#%2:\"\"6:7;/,#;9/#$+\")(\"'#&'#.\" &\"/'$8\":\xEC\" )(\"'#&'#"), - peg$decode("%;:.c &%;\x97/Y#$%;A/,#;\x97/#$+\")(\"'#&'#06*%;A/,#;\x97/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/& 8!:\xED! )"), - peg$decode("%;L.# &;\x98/]#$%;B/,#;\x9A/#$+\")(\"'#&'#06*%;B/,#;\x9A/#$+\")(\"'#&'#&/'$8\":\xEE\" )(\"'#&'#"), - peg$decode("%;\x99.\" &\"/>#;@/5$;M/,$;?/#$+$)($'#(#'#(\"'#&'#"), - peg$decode("%%;6/Y#$%;./,#;6/#$+\")(\"'#&'#06*%;./,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#.# &;H/' 8!:\xEF!! )"), - peg$decode(";\x9B.) &;\x9C.# &;\x9F"), - peg$decode("%3\xF0\"\"5!7\xF1/:#;$;\xCE/5$;./,$;\x8F/#$+%)(%'#($'#(#'#(\"'#&'#"), - peg$decode("%$;!/�#*;!&&&#/' 8!:\u0149!! )"), - peg$decode("%;\xD0/]#$%;A/,#;\xD0/#$+\")(\"'#&'#06*%;A/,#;\xD0/#$+\")(\"'#&'#&/'$8\":\u014A\" )(\"'#&'#"), - peg$decode("%;\x98/]#$%;B/,#;\x9F/#$+\")(\"'#&'#06*%;B/,#;\x9F/#$+\")(\"'#&'#&/'$8\":\u014B\" )(\"'#&'#"), - peg$decode("%;L.O &;\x98.I &%;@.\" &\"/:#;t/1$;?.\" &\"/#$+#)(#'#(\"'#&'#/]#$%;B/,#;\x9F/#$+\")(\"'#&'#06*%;B/,#;\x9F/#$+\")(\"'#&'#&/'$8\":\u014C\" )(\"'#&'#"), - peg$decode("%;\xD3/]#$%;B/,#;\xD4/#$+\")(\"'#&'#06*%;B/,#;\xD4/#$+\")(\"'#&'#&/'$8\":\u014D\" )(\"'#&'#"), - peg$decode("%;\x95/& 8!:\u014E! )"), - peg$decode("%3\u014F\"\"5(7\u0150/:#;$;6/5$;;/,$;\xEB/#$+%)(%'#($'#(#'#(\"'#&'#"), - peg$decode("%3\x92\"\"5#7\xD3.# &;6/' 8!:\u0189!! )"), - peg$decode("%3\xB1\"\"5#7\u018A.G &3\xB3\"\"5#7\u018B.; &3\xB7\"\"5#7\u018C./ &3\xB5\"\"5$7\u018D.# &;6/' 8!:\u018E!! )"), - peg$decode("%;\xED/D#%;C/,#;\xEE/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"), - peg$decode("%;U.) &;\\.# &;X/& 8!:\u018F! )"), - peg$decode("%%;!.\" &\"/[#;!.\" &\"/M$;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+%)(%'#($'#(#'#(\"'#&'#/' 8!:\u0190!! )"), - peg$decode("%%;!/?#;!.\" &\"/1$;!.\" &\"/#$+#)(#'#(\"'#&'#/' 8!:\u0191!! )"), - peg$decode(";\xBD"), - peg$decode("%;\x9D/^#$%;B/,#;\xF2/#$+\")(\"'#&'#06*%;B/,#;\xF2/#$+\")(\"'#&'#&/($8\":\u0192\"!!)(\"'#&'#"), - peg$decode(";\xF3.# &;\x9F"), - peg$decode("%2\u0193\"\"6\u01937\u0194/L#;\"\"6>7?"), - peg$decode("%;\xFF/b#28\"\"6879/S$;\xFA/J$%2\u01A1\"\"6\u01A17\u01A2/,#;\xEB/#$+\")(\"'#&'#.\" &\"/#$+$)($'#(#'#(\"'#&'#"), - peg$decode("%3\u01A3\"\"5%7\u01A4.) &3\u01A5\"\"5$7\u01A6/' 8!:\u019F!! )"), - peg$decode("%;\xEB/O#3\xB1\"\"5#7\xB2.6 &3\xB3\"\"5#7\xB4.* &$;+0#*;+&/'$8\":\u01A7\" )(\"'#&'#"), - peg$decode("%;\u0103/\x87#2F\"\"6F7G/x$;\u0102/o$2F\"\"6F7G/`$;\u0102/W$2F\"\"6F7G/H$;\u0102/?$2F\"\"6F7G/0$;\u0104/'$8):\u01A8) )()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#"), - peg$decode("%;#/>#;#/5$;#/,$;#/#$+$)($'#(#'#(\"'#&'#"), - peg$decode("%;\u0102/,#;\u0102/#$+\")(\"'#&'#"), - peg$decode("%;\u0102/5#;\u0102/,$;\u0102/#$+#)(#'#(\"'#&'#"), - peg$decode("%;\x84/U#;'/L$;\x91/C$;'/:$;\x8F/1$; .\" &\"/#$+&)(&'#(%'#($'#(#'#(\"'#&'#"), - peg$decode("%2\u01A9\"\"6\u01A97\u01AA.) &2\u01AB\"\"6\u01AB7\u01AC/w#;0/n$;\u0107/e$$%;B/2#;\u0108.# &;\x9F/#$+\")(\"'#&'#0<*%;B/2#;\u0108.# &;\x9F/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"), - peg$decode(";\x98.# &;L"), - peg$decode("%2\u01AD\"\"6\u01AD7\u01AE/5#; peg$maxFailPos) { - peg$maxFailPos = peg$currPos; - peg$maxFailExpected = []; - } - - peg$maxFailExpected.push(expected); - } - - function peg$buildSimpleError(message, location) { - return new peg$SyntaxError(message, null, null, location); - } - - function peg$buildStructuredError(expected, found, location) { - return new peg$SyntaxError( - peg$SyntaxError.buildMessage(expected, found), - expected, - found, - location - ); - } - - function peg$decode(s) { - var bc = new Array(s.length), i; - - for (i = 0; i < s.length; i++) { - bc[i] = s.charCodeAt(i) - 32; - } - - return bc; - } - - function peg$parseRule(index) { - var bc = peg$bytecode[index], - ip = 0, - ips = [], - end = bc.length, - ends = [], - stack = [], - params, i; - - while (true) { - while (ip < end) { - switch (bc[ip]) { - case 0: - stack.push(peg$consts[bc[ip + 1]]); - ip += 2; - break; - - case 1: - stack.push(void 0); - ip++; - break; - - case 2: - stack.push(null); - ip++; - break; - - case 3: - stack.push(peg$FAILED); - ip++; - break; - - case 4: - stack.push([]); - ip++; - break; - - case 5: - stack.push(peg$currPos); - ip++; - break; - - case 6: - stack.pop(); - ip++; - break; - - case 7: - peg$currPos = stack.pop(); - ip++; - break; - - case 8: - stack.length -= bc[ip + 1]; - ip += 2; - break; - - case 9: - stack.splice(-2, 1); - ip++; - break; - - case 10: - stack[stack.length - 2].push(stack.pop()); - ip++; - break; - - case 11: - stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1])); - ip += 2; - break; - - case 12: - stack.push(input.substring(stack.pop(), peg$currPos)); - ip++; - break; - - case 13: - ends.push(end); - ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); - - if (stack[stack.length - 1]) { - end = ip + 3 + bc[ip + 1]; - ip += 3; - } else { - end = ip + 3 + bc[ip + 1] + bc[ip + 2]; - ip += 3 + bc[ip + 1]; - } - - break; - - case 14: - ends.push(end); - ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); - - if (stack[stack.length - 1] === peg$FAILED) { - end = ip + 3 + bc[ip + 1]; - ip += 3; - } else { - end = ip + 3 + bc[ip + 1] + bc[ip + 2]; - ip += 3 + bc[ip + 1]; - } - - break; - - case 15: - ends.push(end); - ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); - - if (stack[stack.length - 1] !== peg$FAILED) { - end = ip + 3 + bc[ip + 1]; - ip += 3; - } else { - end = ip + 3 + bc[ip + 1] + bc[ip + 2]; - ip += 3 + bc[ip + 1]; - } - - break; - - case 16: - if (stack[stack.length - 1] !== peg$FAILED) { - ends.push(end); - ips.push(ip); - - end = ip + 2 + bc[ip + 1]; - ip += 2; - } else { - ip += 2 + bc[ip + 1]; - } - - break; - - case 17: - ends.push(end); - ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); - - if (input.length > peg$currPos) { - end = ip + 3 + bc[ip + 1]; - ip += 3; - } else { - end = ip + 3 + bc[ip + 1] + bc[ip + 2]; - ip += 3 + bc[ip + 1]; - } - - break; - - case 18: - ends.push(end); - ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]); - - if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]) { - end = ip + 4 + bc[ip + 2]; - ip += 4; - } else { - end = ip + 4 + bc[ip + 2] + bc[ip + 3]; - ip += 4 + bc[ip + 2]; - } - - break; - - case 19: - ends.push(end); - ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]); - - if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]) { - end = ip + 4 + bc[ip + 2]; - ip += 4; - } else { - end = ip + 4 + bc[ip + 2] + bc[ip + 3]; - ip += 4 + bc[ip + 2]; - } - - break; - - case 20: - ends.push(end); - ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]); - - if (peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))) { - end = ip + 4 + bc[ip + 2]; - ip += 4; - } else { - end = ip + 4 + bc[ip + 2] + bc[ip + 3]; - ip += 4 + bc[ip + 2]; - } - - break; - - case 21: - stack.push(input.substr(peg$currPos, bc[ip + 1])); - peg$currPos += bc[ip + 1]; - ip += 2; - break; - - case 22: - stack.push(peg$consts[bc[ip + 1]]); - peg$currPos += peg$consts[bc[ip + 1]].length; - ip += 2; - break; - - case 23: - stack.push(peg$FAILED); - if (peg$silentFails === 0) { - peg$fail(peg$consts[bc[ip + 1]]); - } - ip += 2; - break; - - case 24: - peg$savedPos = stack[stack.length - 1 - bc[ip + 1]]; - ip += 2; - break; - - case 25: - peg$savedPos = peg$currPos; - ip++; - break; - - case 26: - params = bc.slice(ip + 4, ip + 4 + bc[ip + 3]); - for (i = 0; i < bc[ip + 3]; i++) { - params[i] = stack[stack.length - 1 - params[i]]; - } - - stack.splice( - stack.length - bc[ip + 2], - bc[ip + 2], - peg$consts[bc[ip + 1]].apply(null, params) - ); - - ip += 4 + bc[ip + 3]; - break; - - case 27: - stack.push(peg$parseRule(bc[ip + 1])); - ip += 2; - break; - - case 28: - peg$silentFails++; - ip++; - break; - - case 29: - peg$silentFails--; - ip++; - break; - - default: - throw new Error("Invalid opcode: " + bc[ip] + "."); - } - } - - if (ends.length > 0) { - end = ends.pop(); - ip = ips.pop(); - } else { - break; - } - } - - return stack[0]; - } - - - options.data = {}; // Object to which header attributes will be assigned during parsing - - function list (head, tail) { - return [head].concat(tail); - } - - - peg$result = peg$parseRule(peg$startRuleIndex); - - if (peg$result !== peg$FAILED && peg$currPos === input.length) { - return peg$result; - } else { - if (peg$result !== peg$FAILED && peg$currPos < input.length) { - peg$fail(peg$endExpectation()); - } - - throw peg$buildStructuredError( - peg$maxFailExpected, - peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, - peg$maxFailPos < input.length - ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) - : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) - ); - } -} - -module.exports = { - SyntaxError: peg$SyntaxError, - parse: peg$parse -}; - - -/***/ }), -/* 32 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * @name SIP - * @namespace - */ - - -module.exports = function (SIP) { - var Modifiers; - - Modifiers = { - stripTcpCandidates: function stripTcpCandidates(description) { - description.sdp = description.sdp.replace(/^a=candidate:\d+ \d+ tcp .*?\r\n/img, ""); - return SIP.Utils.Promise.resolve(description); - }, - - stripTelephoneEvent: function stripTelephoneEvent(description) { - description.sdp = description.sdp.replace(/^a=rtpmap:\d+ telephone-event\/d+/img, ""); - return SIP.Utils.Promise.resolve(description); - }, - - cleanJitsiSdpImageattr: function cleanJitsiSdpImageattr(description) { - description.sdp = description.sdp.replace(/^(a=imageattr:.*?)(x|y)=\[0-/gm, "$1$2=[1:"); - return SIP.Utils.Promise.resolve(description); - }, - - stripG722: function stripG722(description) { - var parts = description.sdp.match(/^m=audio.*$/gm); - if (parts) { - var mline = parts[0]; - mline = mline.split(" "); - // Ignore the first 3 parameters of the mline. The codec information is after that - for (var i = 3; i < mline.length; i = i + 1) { - if (mline[i] === "9") { - mline.splice(i, 1); - var numberOfCodecs = parseInt(mline[1], 10); - numberOfCodecs = numberOfCodecs - 1; - mline[1] = numberOfCodecs.toString(); - } - } - mline = mline.join(" "); - description.sdp = description.sdp.replace(/^m=audio.*$/gm, mline); - description.sdp = description.sdp.replace(/^a=rtpmap:.*G722\/8000\r\n?/gm, "").replace(); - } - return SIP.Utils.Promise.resolve(description); - } - }; - - return Modifiers; -}; - -/***/ }), -/* 33 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -/** - * @fileoverview Simple - */ - -/* Simple - * @class Simple - */ - -module.exports = function (SIP) { - - var C = { - STATUS_NULL: 0, - STATUS_NEW: 1, - STATUS_CONNECTING: 2, - STATUS_CONNECTED: 3, - STATUS_COMPLETED: 4 - }; - - /* - * @param {Object} options - */ - var Simple = function Simple(options) { - /* - * { - * media: { - * remote: { - * audio: , - * video: - * }, - * local: { - * video: - * } - * }, - * ua: { - * - * } - * } - */ - - if (options.media.remote.video) { - this.video = true; - } else { - this.video = false; - } - - if (options.media.remote.audio) { - this.audio = true; - } else { - this.audio = false; - } - - if (!this.audio && !this.video) { - // Need to do at least audio or video - // Error - throw new Error('At least one remote audio or video element is required for Simple.'); - } - - this.options = options; - - // https://stackoverflow.com/questions/7944460/detect-safari-browser - var browserUa = global.navigator.userAgent.toLowerCase(); - var isSafari = false; - if (browserUa.indexOf('safari') > -1 && browserUa.indexOf('chrome') < 0) { - isSafari = true; - } - var sessionDescriptionHandlerFactoryOptions = {}; - if (isSafari) { - sessionDescriptionHandlerFactoryOptions.modifiers = [SIP.WebRTC.Modifiers.stripG722]; - } - - if (!this.options.ua.uri) { - this.anonymous = true; - } - - this.ua = new SIP.UA({ - // User Configurable Options - wsServers: this.options.ua.wsServers, - uri: this.options.ua.uri, - authorizationUser: this.options.ua.authorizationUser, - password: this.options.ua.password, - displayName: this.options.ua.displayName, - // Undocumented "Advanced" Options - traceSip: this.options.ua.traceSip, - userAgentString: this.options.ua.userAgentString, - // Fixed Options - register: true, - sessionDescriptionHandlerFactoryOptions: sessionDescriptionHandlerFactoryOptions - }); - - this.state = C.STATUS_NULL; - - this.logger = this.ua.getLogger('sip.simple'); - - this.ua.on('registered', function () { - this.emit('registered', this.ua); - }.bind(this)); - - this.ua.on('unregistered', function () { - this.emit('unregistered', this.ua); - }.bind(this)); - - this.ua.on('failed', function () { - this.emit('unregistered', this.ua); - }.bind(this)); - - this.ua.on('invite', function (session) { - // If there is already an active session reject the incoming session - if (this.state !== C.STATUS_NULL && this.state !== C.STATUS_COMPLETED) { - this.logger.warn('Rejecting incoming call. Simple only supports 1 call at a time'); - session.reject(); - return; - } - this.session = session; - this.setupSession(); - this.emit('ringing', this.session); - }.bind(this)); - - this.ua.on('message', function (message) { - this.emit('message', message); - }.bind(this)); - - return this; - }; - - Simple.prototype = Object.create(SIP.EventEmitter.prototype); - Simple.C = C; - - // Public - - Simple.prototype.call = function (destination) { - if (!this.ua || !this.checkRegistration()) { - this.logger.warn('A registered UA is required for calling'); - return; - } - if (this.state !== C.STATUS_NULL && this.state !== C.STATUS_COMPLETED) { - this.logger.warn('Cannot make more than a single call with Simple'); - return; - } - // Safari hack, because you cannot call .play() from a non user action - if (this.options.media.remote.audio) { - this.options.media.remote.audio.autoplay = true; - } - if (this.options.media.remote.video) { - this.options.media.remote.video.autoplay = true; - } - if (this.options.media.local && this.options.media.local.video) { - this.options.media.local.video.autoplay = true; - this.options.media.local.video.volume = 0; - } - this.session = this.ua.invite(destination, { - sessionDescriptionHandlerOptions: { - constraints: { - audio: this.audio, - video: this.video - } - } - }); - this.setupSession(); - - return this.session; - }; - - Simple.prototype.answer = function () { - if (this.state !== C.STATUS_NEW && this.state !== C.STATUS_CONNECTING) { - this.logger.warn('No call to answer'); - return; - } - // Safari hack, because you cannot call .play() from a non user action - if (this.options.media.remote.audio) { - this.options.media.remote.audio.autoplay = true; - } - if (this.options.media.remote.video) { - this.options.media.remote.video.autoplay = true; - } - return this.session.accept({ - sessionDescriptionHandlerOptions: { - constraints: { - audio: this.audio, - video: this.video - } - } - }); - // emit call is active - }; - - Simple.prototype.reject = function () { - if (this.state !== C.STATUS_NEW && this.state !== C.STATUS_CONNECTING) { - this.logger.warn('Call is already answered'); - return; - } - return this.session.reject(); - }; - - Simple.prototype.hangup = function () { - if (this.state !== C.STATUS_CONNECTED && this.state !== C.STATUS_CONNECTING && this.state !== C.STATUS_NEW) { - this.logger.warn('No active call to hang up on'); - return; - } - if (this.state !== C.STATUS_CONNECTED) { - return this.session.cancel(); - } else { - return this.session.bye(); - } - }; - - Simple.prototype.hold = function () { - if (this.state !== C.STATUS_CONNECTED || this.session.local_hold) { - this.logger.warn('Cannot put call on hold'); - return; - } - this.mute(); - this.logger.log('Placing session on hold'); - return this.session.hold(); - }; - - Simple.prototype.unhold = function () { - if (this.state !== C.STATUS_CONNECTED || !this.session.local_hold) { - this.logger.warn('Cannot unhold a call that is not on hold'); - return; - } - this.unmute(); - this.logger.log('Placing call off hold'); - return this.session.unhold(); - }; - - Simple.prototype.mute = function () { - if (this.state !== C.STATUS_CONNECTED) { - this.logger.warn('An acitve call is required to mute audio'); - return; - } - this.logger.log('Muting Audio'); - this.toggleMute(true); - }; - - Simple.prototype.unmute = function () { - if (this.state !== C.STATUS_CONNECTED) { - this.logger.warn('An active call is required to unmute audio'); - return; - } - this.logger.log('Unmuting Audio'); - this.toggleMute(false); - }; - - Simple.prototype.sendDTMF = function (tone) { - if (this.state !== C.STATUS_CONNECTED) { - this.logger.warn('An active call is required to send a DTMF tone'); - return; - } - this.logger.log('Sending DTMF tone: ' + tone); - this.session.dtmf(tone); - }; - - Simple.prototype.message = function (destination, message) { - if (!this.ua || !this.checkRegistration()) { - this.logger.warn('A registered UA is required to send a message'); - return; - } - if (!destination || !message) { - this.logger.warn('A destination and message are required to send a message'); - return; - } - this.ua.message(destination, message); - }; - - // Private Helpers - - Simple.prototype.checkRegistration = function () { - return this.anonymous || this.ua && this.ua.isRegistered(); - }; - - Simple.prototype.setupRemoteMedia = function () { - // If there is a video track, it will attach the video and audio to the same element - var pc = this.session.sessionDescriptionHandler.peerConnection; - var remoteStream; - - if (pc.getReceivers) { - remoteStream = new global.window.MediaStream(); - pc.getReceivers().forEach(function (receiver) { - var track = receiver.track; - if (track) { - remoteStream.addTrack(track); - } - }); - } else { - remoteStream = pc.getRemoteStreams()[0]; - } - if (this.video) { - this.options.media.remote.video.srcObject = remoteStream; - this.options.media.remote.video.play().catch(function () { - this.logger.log('play was rejected'); - }.bind(this)); - } else if (this.audio) { - this.options.media.remote.audio.srcObject = remoteStream; - this.options.media.remote.audio.play().catch(function () { - this.logger.log('play was rejected'); - }.bind(this)); - } - }; - - Simple.prototype.setupLocalMedia = function () { - if (this.video && this.options.media.local && this.options.media.local.video) { - var pc = this.session.sessionDescriptionHandler.peerConnection; - var localStream; - if (pc.getSenders) { - localStream = new global.window.MediaStream(); - pc.getSenders().forEach(function (sender) { - var track = sender.track; - if (track && track.kind === 'video') { - localStream.addTrack(track); - } - }); - } else { - localStream = pc.getLocalStreams()[0]; - } - this.options.media.local.video.srcObject = localStream; - this.options.media.local.video.volume = 0; - this.options.media.local.video.play(); - } - }; - - Simple.prototype.cleanupMedia = function () { - if (this.video) { - this.options.media.remote.video.srcObject = null; - this.options.media.remote.video.pause(); - if (this.options.media.local && this.options.media.local.video) { - this.options.media.local.video.srcObject = null; - this.options.media.local.video.pause(); - } - } - if (this.audio) { - this.options.media.remote.audio.srcObject = null; - this.options.media.remote.audio.pause(); - } - }; - - Simple.prototype.setupSession = function () { - this.state = C.STATUS_NEW; - this.emit('new', this.session); - - this.session.on('progress', this.onProgress.bind(this)); - this.session.on('accepted', this.onAccepted.bind(this)); - this.session.on('rejected', this.onEnded.bind(this)); - this.session.on('failed', this.onFailed.bind(this)); - this.session.on('terminated', this.onEnded.bind(this)); - }; - - Simple.prototype.destroyMedia = function () { - this.session.sessionDescriptionHandler.close(); - }; - - Simple.prototype.toggleMute = function (mute) { - var pc = this.session.sessionDescriptionHandler.peerConnection; - if (pc.getSenders) { - pc.getSenders().forEach(function (sender) { - if (sender.track) { - sender.track.enabled = !mute; - } - }); - } else { - pc.getLocalStreams().forEach(function (stream) { - stream.getAudioTracks().forEach(function (track) { - track.enabled = !mute; - }); - stream.getVideoTracks().forEach(function (track) { - track.enabled = !mute; - }); - }); - } - }; - - Simple.prototype.onAccepted = function () { - this.state = C.STATUS_CONNECTED; - this.emit('connected', this.session); - - this.setupLocalMedia(); - this.setupRemoteMedia(); - this.session.sessionDescriptionHandler.on('addTrack', function () { - this.logger.log('A track has been added, triggering new remoteMedia setup'); - this.setupRemoteMedia(); - }.bind(this)); - - this.session.sessionDescriptionHandler.on('addStream', function () { - this.logger.log('A stream has been added, trigger new remoteMedia setup'); - this.setupRemoteMedia(); - }.bind(this)); - - this.session.on('hold', function () { - this.emit('hold', this.session); - }.bind(this)); - this.session.on('unhold', function () { - this.emit('unhold', this.session); - }.bind(this)); - this.session.on('dtmf', function (tone) { - this.emit('dtmf', tone); - }.bind(this)); - this.session.on('bye', this.onEnded.bind(this)); - }; - - Simple.prototype.onProgress = function () { - this.state = C.STATUS_CONNECTING; - this.emit('connecting', this.session); - }; - - Simple.prototype.onFailed = function () { - this.onEnded(); - }; - - Simple.prototype.onEnded = function () { - this.state = C.STATUS_COMPLETED; - this.emit('ended', this.session); - this.cleanupMedia(); - }; - - return Simple; -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - -/***/ }), -/* 34 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { - -var toplevel = global.window || global; - -function getPrefixedProperty(object, name) { - if (object == null) { - return; - } - var capitalizedName = name.charAt(0).toUpperCase() + name.slice(1); - var prefixedNames = [name, 'webkit' + capitalizedName, 'moz' + capitalizedName]; - for (var i in prefixedNames) { - var property = object[prefixedNames[i]]; - if (property) { - return property.bind(object); - } - } -} - -module.exports = { - WebSocket: toplevel.WebSocket, - Transport: __webpack_require__(35), - open: toplevel.open, - Promise: toplevel.Promise, - timers: toplevel, - - // Console is not defined in ECMAScript, so just in case... - console: toplevel.console || { - debug: function debug() {}, - log: function log() {}, - warn: function warn() {}, - error: function error() {} - }, - - addEventListener: getPrefixedProperty(toplevel, 'addEventListener'), - removeEventListener: getPrefixedProperty(toplevel, 'removeEventListener') -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - -/***/ }), -/* 35 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview Transport - */ - -/** - * @augments SIP - * @class Transport - * @param {SIP.UA} ua - * @param {Object} server ws_server Object - */ - -module.exports = function (SIP, WebSocket) { - var Transport, - C = { - // Transport status codes - STATUS_READY: 0, - STATUS_DISCONNECTED: 1, - STATUS_ERROR: 2 - }; - - /** - * Compute an amount of time in seconds to wait before sending another - * keep-alive. - * @returns {Number} - */ - function computeKeepAliveTimeout(upperBound) { - var lowerBound = upperBound * 0.8; - return 1000 * (Math.random() * (upperBound - lowerBound) + lowerBound); - } - - Transport = function Transport(ua, server) { - - this.logger = ua.getLogger('sip.transport'); - this.ua = ua; - this.ws = null; - this.server = server; - this.reconnection_attempts = 0; - this.closed = false; - this.connected = false; - this.reconnectTimer = null; - this.lastTransportError = {}; - - this.keepAliveInterval = ua.configuration.keepAliveInterval; - this.keepAliveTimeout = null; - this.keepAliveTimer = null; - - this.ua.transport = this; - - // Connect - this.connect(); - }; - - Transport.prototype = { - /** - * Send a message. - * @param {SIP.OutgoingRequest|String} msg - * @returns {Boolean} - */ - send: function send(msg) { - var message = msg.toString(); - - if (this.ws && this.ws.readyState === WebSocket.OPEN) { - if (this.ua.configuration.traceSip === true) { - this.logger.log('sending WebSocket message:\n\n' + message + '\n'); - } - this.ws.send(message); - return true; - } else { - this.logger.warn('unable to send message, WebSocket is not open'); - return false; - } - }, - - /** - * Send a keep-alive (a double-CRLF sequence). - * @private - * @returns {Boolean} - */ - sendKeepAlive: function sendKeepAlive() { - if (this.keepAliveTimeout) { - return; - } - - this.keepAliveTimeout = SIP.Timers.setTimeout(function () { - this.ua.emit('keepAliveTimeout'); - }.bind(this), 10000); - - return this.send('\r\n\r\n'); - }, - - /** - * Start sending keep-alives. - * @private - */ - startSendingKeepAlives: function startSendingKeepAlives() { - if (this.keepAliveInterval && !this.keepAliveTimer) { - this.keepAliveTimer = SIP.Timers.setTimeout(function () { - this.sendKeepAlive(); - this.keepAliveTimer = null; - this.startSendingKeepAlives(); - }.bind(this), computeKeepAliveTimeout(this.keepAliveInterval)); - } - }, - - /** - * Stop sending keep-alives. - * @private - */ - stopSendingKeepAlives: function stopSendingKeepAlives() { - SIP.Timers.clearTimeout(this.keepAliveTimer); - SIP.Timers.clearTimeout(this.keepAliveTimeout); - this.keepAliveTimer = null; - this.keepAliveTimeout = null; - }, - - /** - * Disconnect socket. - */ - disconnect: function disconnect() { - if (this.ws) { - // Clear reconnectTimer - SIP.Timers.clearTimeout(this.reconnectTimer); - - this.stopSendingKeepAlives(); - - this.closed = true; - this.logger.log('closing WebSocket ' + this.server.ws_uri); - this.ws.close(); - this.ws = null; - } - - if (this.reconnectTimer !== null) { - SIP.Timers.clearTimeout(this.reconnectTimer); - this.reconnectTimer = null; - this.ua.emit('disconnected', { - transport: this, - code: this.lastTransportError.code, - reason: this.lastTransportError.reason - }); - } - }, - - /** - * Connect socket. - */ - connect: function connect() { - var transport = this; - - if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) { - this.logger.log('WebSocket ' + this.server.ws_uri + ' is already connected'); - return false; - } - - if (this.ws) { - this.ws.close(); - this.ws = null; - } - - this.logger.log('connecting to WebSocket ' + this.server.ws_uri); - this.ua.onTransportConnecting(this, this.reconnection_attempts === 0 ? 1 : this.reconnection_attempts); - - try { - this.ws = new WebSocket(this.server.ws_uri, 'sip'); - } catch (e) { - this.logger.warn('error connecting to WebSocket ' + this.server.ws_uri + ': ' + e); - } - - this.ws.binaryType = 'arraybuffer'; - - this.ws.onopen = function () { - transport.onOpen(); - }; - - this.ws.onclose = function (e) { - transport.onClose(e); - // Always cleanup. Eases GC, prevents potential memory leaks. - this.onopen = null; - this.onclose = null; - this.onmessage = null; - this.onerror = null; - }; - - this.ws.onmessage = function (e) { - transport.onMessage(e); - }; - - this.ws.onerror = function (e) { - transport.onError(e); - }; - }, - - // Transport Event Handlers - - /** - * @event - * @param {event} e - */ - onOpen: function onOpen() { - this.connected = true; - - this.logger.log('WebSocket ' + this.server.ws_uri + ' connected'); - // Clear reconnectTimer since we are not disconnected - if (this.reconnectTimer !== null) { - SIP.Timers.clearTimeout(this.reconnectTimer); - this.reconnectTimer = null; - } - // Reset reconnection_attempts - this.reconnection_attempts = 0; - // Disable closed - this.closed = false; - // Trigger onTransportConnected callback - this.ua.onTransportConnected(this); - // Start sending keep-alives - this.startSendingKeepAlives(); - }, - - /** - * @event - * @param {event} e - */ - onClose: function onClose(e) { - var connected_before = this.connected; - - this.lastTransportError.code = e.code; - this.lastTransportError.reason = e.reason; - - this.stopSendingKeepAlives(); - - if (this.reconnection_attempts > 0) { - this.logger.log('Reconnection attempt ' + this.reconnection_attempts + ' failed (code: ' + e.code + (e.reason ? '| reason: ' + e.reason : '') + ')'); - this.reconnect(); - } else { - this.connected = false; - this.logger.log('WebSocket disconnected (code: ' + e.code + (e.reason ? '| reason: ' + e.reason : '') + ')'); - - if (e.wasClean === false) { - this.logger.warn('WebSocket abrupt disconnection'); - } - // Transport was connected - if (connected_before === true) { - this.ua.onTransportClosed(this); - // Check whether the user requested to close. - if (!this.closed) { - this.reconnect(); - } else { - this.ua.emit('disconnected', { - transport: this, - code: this.lastTransportError.code, - reason: this.lastTransportError.reason - }); - } - } else { - // This is the first connection attempt - //Network error - this.ua.onTransportError(this); - } - } - }, - - /** - * @event - * @param {event} e - */ - onMessage: function onMessage(e) { - var message, - transaction, - data = e.data; - - // CRLF Keep Alive response from server. Ignore it. - if (data === '\r\n') { - SIP.Timers.clearTimeout(this.keepAliveTimeout); - this.keepAliveTimeout = null; - - if (this.ua.configuration.traceSip === true) { - this.logger.log('received WebSocket message with CRLF Keep Alive response'); - } - - return; - } - - // WebSocket binary message. - else if (typeof data !== 'string') { - try { - data = String.fromCharCode.apply(null, new Uint8Array(data)); - } catch (evt) { - this.logger.warn('received WebSocket binary message failed to be converted into string, message discarded'); - return; - } - - if (this.ua.configuration.traceSip === true) { - this.logger.log('received WebSocket binary message:\n\n' + data + '\n'); - } - } - - // WebSocket text message. - else { - if (this.ua.configuration.traceSip === true) { - this.logger.log('received WebSocket text message:\n\n' + data + '\n'); - } - } - - message = SIP.Parser.parseMessage(data, this.ua); - - if (!message) { - return; - } - - if (this.ua.status === SIP.UA.C.STATUS_USER_CLOSED && message instanceof SIP.IncomingRequest) { - return; - } - - // Do some sanity check - if (SIP.sanityCheck(message, this.ua, this)) { - if (message instanceof SIP.IncomingRequest) { - message.transport = this; - this.ua.receiveRequest(message); - } else if (message instanceof SIP.IncomingResponse) { - /* Unike stated in 18.1.2, if a response does not match - * any transaction, it is discarded here and no passed to the core - * in order to be discarded there. - */ - switch (message.method) { - case SIP.C.INVITE: - transaction = this.ua.transactions.ict[message.via_branch]; - if (transaction) { - transaction.receiveResponse(message); - } - break; - case SIP.C.ACK: - // Just in case ;-) - break; - default: - transaction = this.ua.transactions.nict[message.via_branch]; - if (transaction) { - transaction.receiveResponse(message); - } - break; - } - } - } - }, - - /** - * @event - * @param {event} e - */ - onError: function onError(e) { - this.logger.warn('WebSocket connection error: '); - this.logger.warn(e); - }, - - /** - * Reconnection attempt logic. - * @private - */ - reconnect: function reconnect() { - var transport = this; - - this.reconnection_attempts += 1; - - if (this.reconnection_attempts > this.ua.configuration.wsServerMaxReconnection) { - this.logger.warn('maximum reconnection attempts for WebSocket ' + this.server.ws_uri); - this.ua.onTransportError(this); - } else if (this.reconnection_attempts === 1) { - this.logger.log('Connection to WebSocket ' + this.server.ws_uri + ' severed, attempting first reconnect'); - transport.connect(); - } else { - this.logger.log('trying to reconnect to WebSocket ' + this.server.ws_uri + ' (reconnection attempt ' + this.reconnection_attempts + ')'); - - this.reconnectTimer = SIP.Timers.setTimeout(function () { - transport.connect(); - transport.reconnectTimer = null; - }, this.ua.configuration.wsServerReconnectionTimeout * 1000); - } - } - }; - - Transport.C = C; - return Transport; -}; - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/dist/sip-0.9.1.min.js b/dist/sip-0.9.1.min.js deleted file mode 100644 index 4d741f5be..000000000 --- a/dist/sip-0.9.1.min.js +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * - * SIP version 0.9.1 - * Copyright (c) 2014-2017 Junction Networks, Inc - * Homepage: https://sipjs.com - * License: https://sipjs.com/license/ - * - * - * ~~~SIP.js contains substantial portions of JsSIP under the following license~~~ - * Homepage: http://jssip.net - * Copyright (c) 2012-2013 José Luis Millán - Versatica - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * ~~~ end JsSIP license ~~~ - * - * - * - * - */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SIP=t():e.SIP=t()}("undefined"!=typeof self?self:this,function(){return function(e){function t(s){if(i[s])return i[s].exports;var r=i[s]={i:s,l:!1,exports:{}};return e[s].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var i={};return t.m=e,t.c=i,t.d=function(e,i,s){t.o(e,i)||Object.defineProperty(e,i,{configurable:!1,enumerable:!0,get:s})},t.n=function(e){var i=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(i,"a",i),i},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=1)}([function(e,t){var i;i=function(){return this}();try{i=i||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(i=window)}e.exports=i},function(e,t,i){"use strict";e.exports=i(2)(i(34))},function(e,t,i){"use strict";e.exports=function(e){var t=i(3),s=t.version,r=t.title,n=Object.defineProperties({},{version:{get:function(){return s}},name:{get:function(){return r}}});return i(4)(n,e),n.LoggerFactory=i(5)(e.console),n.EventEmitter=i(6)(),n.C=i(8)(n.name,n.version),n.Exceptions=i(9),n.Timers=i(10)(e.timers),n.Transport=e.Transport(n,e.WebSocket),i(11)(n),i(12)(n),i(13)(n),i(14)(n),i(15)(n),i(16)(n),i(18)(n),i(19)(n),n.SessionDescriptionHandler=i(20)(n.EventEmitter),i(21)(n),i(22)(n),i(23)(n),i(25)(n),i(26)(n,e),i(28)(n),n.DigestAuthentication=i(29)(n.Utils),n.Grammar=i(30)(n),n.WebRTC={Modifiers:i(32)(n),Simple:i(33)(n)},n}},function(e,t){e.exports={name:"sip.js",title:"SIP.js",description:"A simple, intuitive, and powerful JavaScript signaling library",version:"0.9.1",main:"dist/sip.min.js",browser:{"./src/environment.js":"./src/environment_browser.js"},homepage:"https://sipjs.com",author:"OnSIP (https://sipjs.com/aboutus/)",contributors:[{url:"https://github.com/onsip/SIP.js/blob/master/THANKS.md"}],repository:{type:"git",url:"https://github.com/onsip/SIP.js.git"},keywords:["sip","websocket","webrtc","library","javascript"],devDependencies:{"babel-core":"^6.26.0","babel-loader":"^7.1.2","babel-preset-env":"^1.6.1",eslint:"^4.9.0","jasmine-core":"^2.8.0",karma:"^1.7.1","karma-cli":"^1.0.1","karma-jasmine":"^1.1.0","karma-jasmine-html-reporter":"^0.2.2","karma-mocha-reporter":"^2.2.5","karma-phantomjs-launcher":"^1.0.4","karma-webpack":"^2.0.6",pegjs:"^0.10.0","pegjs-loader":"^0.5.4","uglifyjs-webpack-plugin":"^1.0.1",webpack:"^3.8.1"},engines:{node:">=4.0"},license:"MIT",scripts:{prebuild:"eslint src/*.js src/**/*.js",build:"webpack --progress && cp dist/sip.js dist/sip-$npm_package_version.js && cp dist/sip.min.js dist/sip-$npm_package_version.min.js",browserTest:"sleep 2 && open http://0.0.0.0:9876/debug.html & karma start --reporters kjhtml --no-single-run",commandLineTest:"karma start --reporters mocha --browsers PhantomJS --single-run",buildAndTest:"npm run build && npm run commandLineTest"},dependencies:{ws:"^1.0.1"},optionalDependencies:{promiscuous:"^0.6.0"}}},function(e,t,i){"use strict";e.exports=function(e,t){var i;i={Promise:t.Promise,defer:function(){var e={};return e.promise=new i.Promise(function(t,i){e.resolve=t,e.reject=i}),e},reducePromises:function(t,i){return t.reduce(function(e,t){return e=e.then(t)},e.Utils.Promise.resolve(i))},augment:function(e,t,i,s){var r,n;n=t.prototype;for(r in n)(s||void 0===e[r])&&(e[r]=n[r]);t.apply(e,i)},optionsOverride:function(e,t,i,s,r,n){s&&e[i]&&r.warn(i+" is deprecated, please use "+t+" instead"),e[t]&&e[i]&&r.warn(t+" overriding "+i),e[t]=e[t]||e[i]||n},str_utf8_length:function(e){return encodeURIComponent(e).replace(/%[A-F\d]{2}/g,"U").length},generateFakeSDP:function(e){if(e){var t=e.indexOf("o="),i=e.indexOf("\r\n",t);return"v=0\r\n"+e.slice(t,i)+"\r\ns=-\r\nt=0 0\r\nc=IN IP4 0.0.0.0"}},isFunction:function(e){return void 0!==e&&"[object Function]"===Object.prototype.toString.call(e)},isDecimal:function(e){return!isNaN(e)&&parseFloat(e)===parseInt(e,10)},createRandomToken:function(e,t){var i,s="";for(t=t||32,i=0;i699)throw new TypeError("Invalid status_code: "+t);if(t)return e.Utils.getReasonHeaderValue(t,i)},buildStatusLine:function(e,t){if(e=e||null,t=t||null,!e||e<100||e>699)throw new TypeError("Invalid status_code: "+e);if(t&&"string"!=typeof t&&!(t instanceof String))throw new TypeError("Invalid reason_phrase: "+t);return t=i.getReasonPhrase(e,t),"SIP/2.0 "+e+" "+t+"\r\n"},getRandomTestNetIP:function(){return"192.0.2."+function(e,t){return Math.floor(Math.random()*(t-e+1)+e)}(1,254)},calculateMD5:function(e){function t(e,t){return e<>>32-t}function i(e,t){var i,s,r,n,o;return r=2147483648&e,n=2147483648&t,i=1073741824&e,s=1073741824&t,o=(1073741823&e)+(1073741823&t),i&s?2147483648^o^r^n:i|s?1073741824&o?3221225472^o^r^n:1073741824^o^r^n:o^r^n}function s(e,s,r,n,o,a,c){return e=i(e,i(i(function(e,t,i){return e&t|~e&i}(s,r,n),o),c)),i(t(e,a),s)}function r(e,s,r,n,o,a,c){return e=i(e,i(i(function(e,t,i){return e&i|t&~i}(s,r,n),o),c)),i(t(e,a),s)}function n(e,s,r,n,o,a,c){return e=i(e,i(i(function(e,t,i){return e^t^i}(s,r,n),o),c)),i(t(e,a),s)}function o(e,s,r,n,o,a,c){return e=i(e,i(i(function(e,t,i){return t^(e|~i)}(s,r,n),o),c)),i(t(e,a),s)}function a(e){var t,i="",s="";for(t=0;t<=3;t++)i+=(s="0"+(e>>>8*t&255).toString(16)).substr(s.length-2,2);return i}var c,h,u,l,d,p,g,f,T,m=[];for(m=function(e){for(var t,i=e.length,s=i+8,r=16*((s-s%64)/64+1),n=Array(r-1),o=0,a=0;a>>29,n}(e=function(e){e=e.replace(/\r\n/g,"\n");for(var t="",i=0;i127&&s<2048?(t+=String.fromCharCode(s>>6|192),t+=String.fromCharCode(63&s|128)):(t+=String.fromCharCode(s>>12|224),t+=String.fromCharCode(s>>6&63|128),t+=String.fromCharCode(63&s|128))}return t}(e)),p=1732584193,g=4023233417,f=2562383102,T=271733878,c=0;c=0&&i<=3?t=i:i>3?t=3:s.hasOwnProperty(i)?t=s[i]:e.error('invalid "level" parameter value: '+JSON.stringify(i))}},connector:{get:function(){return r},set:function(t){null===t||""===t||void 0===t?r=null:"function"==typeof t?r=t:e.error('invalid "connector" parameter value: '+JSON.stringify(t))}}})};return i.prototype.print=function(t,i,s,r){if("string"==typeof r){var n=[new Date,i];s&&n.push(s),r=n.concat(r).join(" | ")}t.call(e,r)},Object.keys(s).forEach(function(r){t.prototype[r]=function(e){this.logger[r](this.category,this.label,e)},i.prototype[r]=function(t,i,n){this.level>=s[r]&&(this.builtinEnabled&&this.print(e[r],t,i,n),this.connector&&this.connector(r,t,i,n))}}),i.prototype.getLogger=function(e,i){var s;return i&&3===this.level?new t(this,e,i):this.loggers[e]?this.loggers[e]:(s=new t(this,e),this.loggers[e]=s,s)},i}},function(e,t,i){"use strict";var s=i(7).EventEmitter;e.exports=function(){function e(){s.call(this)}return e.prototype=Object.create(s.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),e}},function(e,t){function i(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function s(e){return"function"==typeof e}function r(e){return"object"==typeof e&&null!==e}function n(e){return void 0===e}e.exports=i,i.EventEmitter=i,i.prototype._events=void 0,i.prototype._maxListeners=void 0,i.defaultMaxListeners=10,i.prototype.setMaxListeners=function(e){if(!function(e){return"number"==typeof e}(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},i.prototype.emit=function(e){var t,i,o,a,c,h;if(this._events||(this._events={}),"error"===e&&(!this._events.error||r(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var u=new Error('Uncaught, unspecified "error" event. ('+t+")");throw u.context=t,u}if(i=this._events[e],n(i))return!1;if(s(i))switch(arguments.length){case 1:i.call(this);break;case 2:i.call(this,arguments[1]);break;case 3:i.call(this,arguments[1],arguments[2]);break;default:a=Array.prototype.slice.call(arguments,1),i.apply(this,a)}else if(r(i))for(a=Array.prototype.slice.call(arguments,1),o=(h=i.slice()).length,c=0;c0&&this._events[e].length>o&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},i.prototype.on=i.prototype.addListener,i.prototype.once=function(e,t){function i(){this.removeListener(e,i),r||(r=!0,t.apply(this,arguments))}if(!s(t))throw TypeError("listener must be a function");var r=!1;return i.listener=t,this.on(e,i),this},i.prototype.removeListener=function(e,t){var i,n,o,a;if(!s(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(i=this._events[e],o=i.length,n=-1,i===t||s(i.listener)&&i.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(r(i)){for(a=o;a-- >0;)if(i[a]===t||i[a].listener&&i[a].listener===t){n=a;break}if(n<0)return this;1===i.length?(i.length=0,delete this._events[e]):i.splice(n,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},i.prototype.removeAllListeners=function(e){var t,i;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(i=this._events[e],s(i))this.removeListener(e,i);else if(i)for(;i.length;)this.removeListener(e,i[i.length-1]);return delete this._events[e],this},i.prototype.listeners=function(e){return this._events&&this._events[e]?s(this._events[e])?[this._events[e]]:this._events[e].slice():[]},i.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(s(t))return 1;if(t)return t.length}return 0},i.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,i){"use strict";e.exports=function(e,t){return{USER_AGENT:e+"/"+t,SIP:"sip",SIPS:"sips",causes:{CONNECTION_ERROR:"Connection Error",REQUEST_TIMEOUT:"Request Timeout",SIP_FAILURE_CODE:"SIP Failure Code",INTERNAL_ERROR:"Internal Error",BUSY:"Busy",REJECTED:"Rejected",REDIRECTED:"Redirected",UNAVAILABLE:"Unavailable",NOT_FOUND:"Not Found",ADDRESS_INCOMPLETE:"Address Incomplete",INCOMPATIBLE_SDP:"Incompatible SDP",AUTHENTICATION_ERROR:"Authentication Error",DIALOG_ERROR:"Dialog Error",WEBRTC_NOT_SUPPORTED:"WebRTC Not Supported",WEBRTC_ERROR:"WebRTC Error",CANCELED:"Canceled",NO_ANSWER:"No Answer",EXPIRES:"Expires",NO_ACK:"No ACK",NO_PRACK:"No PRACK",USER_DENIED_MEDIA_ACCESS:"User Denied Media Access",BAD_MEDIA_DESCRIPTION:"Bad Media Description",RTP_TIMEOUT:"RTP Timeout"},supported:{UNSUPPORTED:"none",SUPPORTED:"supported",REQUIRED:"required"},SIP_ERROR_CAUSES:{REDIRECTED:[300,301,302,305,380],BUSY:[486,600],REJECTED:[403,603],NOT_FOUND:[404,604],UNAVAILABLE:[480,410,408,430],ADDRESS_INCOMPLETE:[484],INCOMPATIBLE_SDP:[488,606],AUTHENTICATION_ERROR:[401,407]},ACK:"ACK",BYE:"BYE",CANCEL:"CANCEL",INFO:"INFO",INVITE:"INVITE",MESSAGE:"MESSAGE",NOTIFY:"NOTIFY",OPTIONS:"OPTIONS",REGISTER:"REGISTER",UPDATE:"UPDATE",SUBSCRIBE:"SUBSCRIBE",REFER:"REFER",PRACK:"PRACK",REASON_PHRASE:{100:"Trying",180:"Ringing",181:"Call Is Being Forwarded",182:"Queued",183:"Session Progress",199:"Early Dialog Terminated",200:"OK",202:"Accepted",204:"No Notification",300:"Multiple Choices",301:"Moved Permanently",302:"Moved Temporarily",305:"Use Proxy",380:"Alternative Service",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",410:"Gone",412:"Conditional Request Failed",413:"Request Entity Too Large",414:"Request-URI Too Long",415:"Unsupported Media Type",416:"Unsupported URI Scheme",417:"Unknown Resource-Priority",420:"Bad Extension",421:"Extension Required",422:"Session Interval Too Small",423:"Interval Too Brief",428:"Use Identity Header",429:"Provide Referrer Identity",430:"Flow Failed",433:"Anonymity Disallowed",436:"Bad Identity-Info",437:"Unsupported Certificate",438:"Invalid Identity Header",439:"First Hop Lacks Outbound Support",440:"Max-Breadth Exceeded",469:"Bad Info Package",470:"Consent Needed",478:"Unresolvable Destination",480:"Temporarily Unavailable",481:"Call/Transaction Does Not Exist",482:"Loop Detected",483:"Too Many Hops",484:"Address Incomplete",485:"Ambiguous",486:"Busy Here",487:"Request Terminated",488:"Not Acceptable Here",489:"Bad Event",491:"Request Pending",493:"Undecipherable",494:"Security Agreement Required",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Server Time-out",505:"Version Not Supported",513:"Message Too Large",580:"Precondition Failure",600:"Busy Everywhere",603:"Decline",604:"Does Not Exist Anywhere",606:"Not Acceptable"},OPTION_TAGS:{"100rel":!0,199:!0,answermode:!0,"early-session":!0,eventlist:!0,explicitsub:!0,"from-change":!0,"geolocation-http":!0,"geolocation-sip":!0,gin:!0,gruu:!0,histinfo:!0,ice:!0,join:!0,"multiple-refer":!0,norefersub:!0,nosub:!0,outbound:!0,path:!0,policy:!0,precondition:!0,pref:!0,privacy:!0,"recipient-list-invite":!0,"recipient-list-message":!0,"recipient-list-subscribe":!0,replaces:!0,"resource-priority":!0,"sdp-anat":!0,"sec-agree":!0,tdialog:!0,timer:!0,uui:!0}}}},function(e,t,i){"use strict";e.exports={ConfigurationError:function(){var e=function(e,t){this.code=1,this.name="CONFIGURATION_ERROR",this.parameter=e,this.value=t,this.message=this.value?"Invalid value "+JSON.stringify(this.value)+' for parameter "'+this.parameter+'"':"Missing parameter: "+this.parameter};return e.prototype=new Error,e}(),InvalidStateError:function(){var e=function(e){this.code=2,this.name="INVALID_STATE_ERROR",this.status=e,this.message="Invalid status: "+e};return e.prototype=new Error,e}(),NotSupportedError:function(){var e=function(e){this.code=3,this.name="NOT_SUPPORTED_ERROR",this.message=e};return e.prototype=new Error,e}(),GetDescriptionError:function(){var e=function(e){this.code=4,this.name="GET_DESCRIPTION_ERROR",this.message=e};return e.prototype=new Error,e}(),RenegotiationError:function(){var e=function(e){this.code=5,this.name="RENEGOTIATION_ERROR",this.message=e};return e.prototype=new Error,e}()}},function(e,t,i){"use strict";e.exports=function(e){var t={T1:500,T2:4e3,T4:5e3,TIMER_B:32e3,TIMER_D:0,TIMER_F:32e3,TIMER_H:32e3,TIMER_I:0,TIMER_J:0,TIMER_K:0,TIMER_L:32e3,TIMER_M:32e3,TIMER_N:32e3,PROVISIONAL_RESPONSE_INTERVAL:6e4};return["setTimeout","clearTimeout","setInterval","clearInterval"].forEach(function(i){t[i]=function(){return e[i].apply(e,arguments)}}),t}},function(e,t,i){"use strict";e.exports=function(e){function t(e,t){var i=t,s=0,r=0;if(e.substring(i,i+2).match(/(^\r\n)/))return-2;for(;0===s;){if(-1===(r=e.indexOf("\r\n",i)))return r;!e.substring(r+2,r+4).match(/(^\r\n)/)&&e.charAt(r+2).match(/(^\s+)/)?i=r+2:s=r}return s}function i(t,i,s,r){var n,o,a,c,h=i.indexOf(":",s),u=i.substring(s,h).trim(),l=i.substring(h+1,r).trim();switch(u.toLowerCase()){case"via":case"v":t.addHeader("via",l),1===t.getHeaders("via").length?(c=t.parseHeader("Via"))&&(t.via=c,t.via_branch=c.branch):c=0;break;case"from":case"f":t.setHeader("from",l),(c=t.parseHeader("from"))&&(t.from=c,t.from_tag=c.getParam("tag"));break;case"to":case"t":t.setHeader("to",l),(c=t.parseHeader("to"))&&(t.to=c,t.to_tag=c.getParam("tag"));break;case"record-route":if(-1===(c=e.Grammar.parse(l,"Record_Route"))){c=void 0;break}for(a=c.length,o=0;o",a+=r.to_tag?";tag="+r.to_tag:"",this.to=new e.NameAddrHeader.parse(a),this.setHeader("to",a),d=r.from_uri||s.configuration.uri,c=r.from_displayName||0===r.from_displayName?'"'+r.from_displayName+'" ':s.configuration.displayName?'"'+s.configuration.displayName+'" ':"",c+="<"+(d&&d.toRaw?d.toRaw():d)+">;tag=",c+=r.from_tag||e.Utils.newTag(),this.from=new e.NameAddrHeader.parse(c),this.setHeader("from",c),h=r.call_id||s.configuration.sipjsId+e.Utils.createRandomToken(15),this.call_id=h,this.setHeader("call-id",h),u=r.cseq||Math.floor(1e4*Math.random()),this.cseq=u,this.setHeader("cseq",u+" "+t)}).prototype={setHeader:function(t,i){this.headers[e.Utils.headerize(t)]=i instanceof Array?i:[i]},getHeader:function(t){var i,s,r=this.extraHeaders.length,n=this.headers[e.Utils.headerize(t)];if(n){if(n[0])return n[0]}else for(i=new RegExp("^\\s*"+t+"\\s*:","i"),s=0;s=this.headers[t].length))return s=this.headers[t][i],r=s.raw,s.parsed?s.parsed:-1===(n=e.Grammar.parse(r,t.replace(/-/g,"_")))?(this.headers[t].splice(i,1),void this.logger.warn('error parsing "'+t+'" header field with value "'+r+'"')):(s.parsed=n,n);this.logger.log('not so many "'+t+'" headers present')}else this.logger.log('header "'+t+'" not present')},s:function(e,t){return this.parseHeader(e,t)},setHeader:function(t,i){var s={raw:i};this.headers[e.Utils.headerize(t)]=[s]},toString:function(){return this.data}},((r=function(e){this.logger=e.getLogger("sip.sipmessage"),this.ua=e,this.headers={},this.ruri=null,this.transport=null,this.server_transaction=null}).prototype=new s).reply=function(i,s,r,n,o,a){var c,h,u,l,d,p=this.getHeader("To"),g=0,f=0;if(d=e.Utils.buildStatusLine(i,s),r=(r||[]).slice(),this.method===e.C.INVITE&&i>100&&i<=200)for(u=(c=this.getHeaders("record-route")).length;g100?p+=";tag="+e.Utils.newTag():this.to_tag&&!this.s("to").hasParam("tag")&&(p+=";tag="+this.to_tag),d+="To: "+p+"\r\n",d+="From: "+this.getHeader("From")+"\r\n",d+="Call-ID: "+this.call_id+"\r\n",d+="CSeq: "+this.cseq+" "+this.method+"\r\n",u=r.length,l=0;l100?s+=";tag="+e.Utils.newTag():this.to_tag&&!this.s("to").hasParam("tag")&&(s+=";tag="+this.to_tag),r+="To: "+s+"\r\n",r+="From: "+this.getHeader("From")+"\r\n",r+="Call-ID: "+this.call_id+"\r\n",r+="CSeq: "+this.cseq+" "+this.method+"\r\n",r+="User-Agent: "+this.ua.configuration.userAgentString+"\r\n",r+="Content-Length: 0\r\n\r\n",this.transport.send(r)},(n=function(e){this.logger=e.getLogger("sip.sipmessage"),this.headers={},this.status_code=null,this.reason_phrase=null}).prototype=new s,e.OutgoingRequest=i,e.IncomingRequest=r,e.IncomingResponse=n}},function(e,t,i){"use strict";e.exports=function(e){var t;(t=function(t,i,s,r,n,o){var a,c,h,u;if(!s)throw new TypeError('missing or invalid "host" parameter');t=t||e.C.SIP,this.parameters={},this.headers={};for(a in n)this.setParam(a,n[a]);for(c in o)this.setHeader(c,o[c]);h={scheme:t,user:i,host:s,port:r},u={scheme:t.toLowerCase(),user:i,host:s.toLowerCase(),port:r},Object.defineProperties(this,{_normal:{get:function(){return u}},_raw:{get:function(){return h}},scheme:{get:function(){return u.scheme},set:function(e){h.scheme=e,u.scheme=e.toLowerCase()}},user:{get:function(){return u.user},set:function(e){u.user=h.user=e}},host:{get:function(){return u.host},set:function(e){h.host=e,u.host=e.toLowerCase()}},aor:{get:function(){return u.user+"@"+u.host}},port:{get:function(){return u.port},set:function(e){u.port=h.port=0===e?e:parseInt(e,10)||null}}})}).prototype={setParam:function(e,t){e&&(this.parameters[e.toLowerCase()]=void 0===t||null===t?null:t.toString().toLowerCase())},getParam:function(e){if(e)return this.parameters[e.toLowerCase()]},hasParam:function(e){if(e)return!!this.parameters.hasOwnProperty(e.toLowerCase())},deleteParam:function(e){var t;if(e=e.toLowerCase(),this.parameters.hasOwnProperty(e))return t=this.parameters[e],delete this.parameters[e],t},clearParams:function(){this.parameters={}},setHeader:function(t,i){this.headers[e.Utils.headerize(t)]=i instanceof Array?i:[i]},getHeader:function(t){if(t)return this.headers[e.Utils.headerize(t)]},hasHeader:function(t){if(t)return!!this.headers.hasOwnProperty(e.Utils.headerize(t))},deleteHeader:function(t){var i;if(t=e.Utils.headerize(t),this.headers.hasOwnProperty(t))return i=this.headers[t],delete this.headers[t],i},clearHeaders:function(){this.headers={}},clone:function(){return new t(this._raw.scheme,this._raw.user,this._raw.host,this._raw.port,JSON.parse(JSON.stringify(this.parameters)),JSON.parse(JSON.stringify(this.headers)))},toRaw:function(){return this._toString(this._raw)},toString:function(){return this._toString(this._normal)},_toString:function(t){var i,s,r,n,o=[];n=t.scheme+":",t.scheme.toLowerCase().match("^sips?$")||(n+="//"),t.user&&(n+=e.Utils.escapeUser(t.user)+"@"),n+=t.host,(t.port||0===t.port)&&(n+=":"+t.port);for(s in this.parameters)n+=";"+s,null!==this.parameters[s]&&(n+="="+this.parameters[s]);for(i in this.headers)for(r in this.headers[i])o.push(i+"="+this.headers[i][r]);return o.length>0&&(n+="?"+o.join("&")),n}},t.parse=function(t){return-1!==(t=e.Grammar.parse(t,"SIP_URI"))?t:void 0},e.URI=t}},function(e,t,i){"use strict";e.exports=function(e){var t;(t=function(t,i,s){var r;if(!(t&&t instanceof e.URI))throw new TypeError('missing or invalid "uri" parameter');this.uri=t,this.parameters={};for(r in s)this.setParam(r,s[r]);Object.defineProperties(this,{friendlyName:{get:function(){return this.displayName||t.aor}},displayName:{get:function(){return i},set:function(e){i=0===e?"0":e}}})}).prototype={setParam:function(e,t){e&&(this.parameters[e.toLowerCase()]=void 0===t||null===t?null:t.toString())},getParam:e.URI.prototype.getParam,hasParam:e.URI.prototype.hasParam,deleteParam:e.URI.prototype.deleteParam,clearParams:e.URI.prototype.clearParams,clone:function(){return new t(this.uri.clone(),this.displayName,JSON.parse(JSON.stringify(this.parameters)))},toString:function(){var e,t;e=this.displayName||0===this.displayName?'"'+this.displayName+'" ':"",e+="<"+this.uri.toString()+">";for(t in this.parameters)e+=";"+t,null!==this.parameters[t]&&(e+="="+this.parameters[t]);return e}},t.parse=function(t){return-1!==(t=e.Grammar.parse(t,"Name_Addr_Header"))?t:void 0},e.NameAddrHeader=t}},function(e,t,i){"use strict";e.exports=function(e){function t(e,t,i){var s;return s="SIP/2.0/"+(e.ua.configuration.hackViaTcp?"TCP":t.server.scheme),s+=" "+e.ua.configuration.viaHost+";branch="+i,e.ua.configuration.forceRport&&(s+=";rport"),s}var i={STATUS_TRYING:1,STATUS_PROCEEDING:2,STATUS_CALLING:3,STATUS_ACCEPTED:4,STATUS_COMPLETED:5,STATUS_TERMINATED:6,STATUS_CONFIRMED:7,NON_INVITE_CLIENT:"nict",NON_INVITE_SERVER:"nist",INVITE_CLIENT:"ict",INVITE_SERVER:"ist"},s=function(e,s,r){var n;this.type=i.NON_INVITE_CLIENT,this.transport=r,this.id="z9hG4bK"+Math.floor(1e7*Math.random()),this.request_sender=e,this.request=s,this.logger=e.ua.getLogger("sip.transaction.nict",this.id),n=t(e,r,this.id),this.request.setHeader("via",n),this.request_sender.ua.newTransaction(this)};(s.prototype=Object.create(e.EventEmitter.prototype)).stateChanged=function(e){this.state=e,this.emit("stateChanged")},s.prototype.send=function(){this.stateChanged(i.STATUS_TRYING),this.F=e.Timers.setTimeout(this.timer_F.bind(this),e.Timers.TIMER_F),this.transport.send(this.request)||this.onTransportError()},s.prototype.onTransportError=function(){this.logger.log("transport error occurred, deleting non-INVITE client transaction "+this.id),e.Timers.clearTimeout(this.F),e.Timers.clearTimeout(this.K),this.stateChanged(i.STATUS_TERMINATED),this.request_sender.ua.destroyTransaction(this),this.request_sender.onTransportError()},s.prototype.timer_F=function(){this.logger.debug("Timer F expired for non-INVITE client transaction "+this.id),this.stateChanged(i.STATUS_TERMINATED),this.request_sender.ua.destroyTransaction(this),this.request_sender.onRequestTimeout()},s.prototype.timer_K=function(){this.stateChanged(i.STATUS_TERMINATED),this.request_sender.ua.destroyTransaction(this)},s.prototype.receiveResponse=function(t){var s=t.status_code;if(s<200)switch(this.state){case i.STATUS_TRYING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_PROCEEDING),this.request_sender.receiveResponse(t)}else switch(this.state){case i.STATUS_TRYING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_COMPLETED),e.Timers.clearTimeout(this.F),408===s?this.request_sender.onRequestTimeout():this.request_sender.receiveResponse(t),this.K=e.Timers.setTimeout(this.timer_K.bind(this),e.Timers.TIMER_K)}};var r=function(e,s,r){var n,o=this;this.type=i.INVITE_CLIENT,this.transport=r,this.id="z9hG4bK"+Math.floor(1e7*Math.random()),this.request_sender=e,this.request=s,this.logger=e.ua.getLogger("sip.transaction.ict",this.id),n=t(e,r,this.id),this.request.setHeader("via",n),this.request_sender.ua.newTransaction(this),this.request.cancel=function(e,t){for(var i=(t=(t||[]).slice()).length,s=null,r=0;r=100&&s<=199)switch(this.state){case i.STATUS_CALLING:this.stateChanged(i.STATUS_PROCEEDING),this.request_sender.receiveResponse(t),this.cancel&&this.transport.send(this.cancel);break;case i.STATUS_PROCEEDING:this.request_sender.receiveResponse(t)}else if(s>=200&&s<=299)switch(this.state){case i.STATUS_CALLING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_ACCEPTED),this.M=e.Timers.setTimeout(this.timer_M.bind(this),e.Timers.TIMER_M),this.request_sender.receiveResponse(t);break;case i.STATUS_ACCEPTED:this.request_sender.receiveResponse(t)}else if(s>=300&&s<=699)switch(this.state){case i.STATUS_CALLING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_COMPLETED),this.sendACK(),this.request_sender.receiveResponse(t);break;case i.STATUS_COMPLETED:this.sendACK()}};var n=function(e,i,s){var r;this.transport=s,this.id="z9hG4bK"+Math.floor(1e7*Math.random()),this.request_sender=e,this.request=i,this.logger=e.ua.getLogger("sip.transaction.nict",this.id),r=t(e,s,this.id),this.request.setHeader("via",r)};(n.prototype=Object.create(e.EventEmitter.prototype)).send=function(){this.transport.send(this.request)||this.onTransportError()},n.prototype.onTransportError=function(){this.logger.log("transport error occurred, for an ACK client transaction "+this.id),this.request_sender.onTransportError()};var o=function(e,t){this.type=i.NON_INVITE_SERVER,this.id=e.via_branch,this.request=e,this.transport=e.transport,this.ua=t,this.last_response="",e.server_transaction=this,this.logger=t.getLogger("sip.transaction.nist",this.id),this.state=i.STATUS_TRYING,t.newTransaction(this)};(o.prototype=Object.create(e.EventEmitter.prototype)).stateChanged=function(e){this.state=e,this.emit("stateChanged")},o.prototype.timer_J=function(){this.logger.debug("Timer J expired for non-INVITE server transaction "+this.id),this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this)},o.prototype.onTransportError=function(){this.transportError||(this.transportError=!0,this.logger.log("transport error occurred, deleting non-INVITE server transaction "+this.id),e.Timers.clearTimeout(this.J),this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this))},o.prototype.receiveResponse=function(t,s){var r=e.Utils.defer();if(100===t)switch(this.state){case i.STATUS_TRYING:this.stateChanged(i.STATUS_PROCEEDING),this.transport.send(s)||this.onTransportError();break;case i.STATUS_PROCEEDING:this.last_response=s,this.transport.send(s)?r.resolve():(this.onTransportError(),r.reject())}else if(t>=200&&t<=699)switch(this.state){case i.STATUS_TRYING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_COMPLETED),this.last_response=s,this.J=e.Timers.setTimeout(this.timer_J.bind(this),e.Timers.TIMER_J),this.transport.send(s)?r.resolve():(this.onTransportError(),r.reject())}return r.promise};var a=function(e,t){this.type=i.INVITE_SERVER,this.id=e.via_branch,this.request=e,this.transport=e.transport,this.ua=t,this.last_response="",e.server_transaction=this,this.logger=t.getLogger("sip.transaction.ist",this.id),this.state=i.STATUS_PROCEEDING,t.newTransaction(this),this.resendProvisionalTimer=null,e.reply(100)};(a.prototype=Object.create(e.EventEmitter.prototype)).stateChanged=function(e){this.state=e,this.emit("stateChanged")},a.prototype.timer_H=function(){this.logger.debug("Timer H expired for INVITE server transaction "+this.id),this.state===i.STATUS_COMPLETED&&this.logger.warn("transactions","ACK for INVITE server transaction was never received, call will be terminated"),this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this)},a.prototype.timer_I=function(){this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this)},a.prototype.timer_L=function(){this.logger.debug("Timer L expired for INVITE server transaction "+this.id),this.state===i.STATUS_ACCEPTED&&(this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this))},a.prototype.onTransportError=function(){this.transportError||(this.transportError=!0,this.logger.log("transport error occurred, deleting INVITE server transaction "+this.id),null!==this.resendProvisionalTimer&&(e.Timers.clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),e.Timers.clearTimeout(this.L),e.Timers.clearTimeout(this.H),e.Timers.clearTimeout(this.I),this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this))},a.prototype.resend_provisional=function(){this.transport.send(this.last_response)||this.onTransportError()},a.prototype.receiveResponse=function(t,s){var r=e.Utils.defer();if(t>=100&&t<=199)switch(this.state){case i.STATUS_PROCEEDING:this.transport.send(s)||this.onTransportError(),this.last_response=s}if(t>100&&t<=199&&this.state===i.STATUS_PROCEEDING)null===this.resendProvisionalTimer&&(this.resendProvisionalTimer=e.Timers.setInterval(this.resend_provisional.bind(this),e.Timers.PROVISIONAL_RESPONSE_INTERVAL));else if(t>=200&&t<=299)switch(this.state){case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_ACCEPTED),this.last_response=s,this.L=e.Timers.setTimeout(this.timer_L.bind(this),e.Timers.TIMER_L),null!==this.resendProvisionalTimer&&(e.Timers.clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null);case i.STATUS_ACCEPTED:this.transport.send(s)?r.resolve():(this.onTransportError(),r.reject())}else if(t>=300&&t<=699)switch(this.state){case i.STATUS_PROCEEDING:null!==this.resendProvisionalTimer&&(e.Timers.clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),this.transport.send(s)?(this.stateChanged(i.STATUS_COMPLETED),this.H=e.Timers.setTimeout(this.timer_H.bind(this),e.Timers.TIMER_H),r.resolve()):(this.onTransportError(),r.reject())}return r.promise};e.Transactions={C:i,checkTransaction:function(t,s){var r;switch(s.method){case e.C.INVITE:if(r=t.transactions.ist[s.via_branch]){switch(r.state){case i.STATUS_PROCEEDING:r.transport.send(r.last_response)}return!0}break;case e.C.ACK:if(!(r=t.transactions.ist[s.via_branch]))return!1;if(r.state===i.STATUS_ACCEPTED)return!1;if(r.state===i.STATUS_COMPLETED)return r.stateChanged(i.STATUS_CONFIRMED),r.I=e.Timers.setTimeout(r.timer_I.bind(r),e.Timers.TIMER_I),!0;break;case e.C.CANCEL:return(r=t.transactions.ist[s.via_branch])?(s.reply_sl(200),r.state!==i.STATUS_PROCEEDING):(s.reply_sl(481),!0);default:if(r=t.transactions.nist[s.via_branch]){switch(r.state){case i.STATUS_TRYING:break;case i.STATUS_PROCEEDING:case i.STATUS_COMPLETED:r.transport.send(r.last_response)}return!0}}},NonInviteClientTransaction:s,InviteClientTransaction:r,AckClientTransaction:n,NonInviteServerTransaction:o,InviteServerTransaction:a}}},function(e,t,i){"use strict";e.exports=function(e){var t,s=i(17)(e),r={STATUS_EARLY:1,STATUS_CONFIRMED:2};(t=function(t,i,s,n){var o;if(this.uac_pending_reply=!1,this.uas_pending_reply=!1,!i.hasHeader("contact"))return{error:"unable to create a Dialog without Contact header field"};n=i instanceof e.IncomingResponse?i.status_code<200?r.STATUS_EARLY:r.STATUS_CONFIRMED:n||r.STATUS_CONFIRMED,o=i.parseHeader("contact"),"UAS"===s?(this.id={call_id:i.call_id,local_tag:i.to_tag,remote_tag:i.from_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this.state=n,this.remote_seqnum=i.cseq,this.local_uri=i.parseHeader("to").uri,this.remote_uri=i.parseHeader("from").uri,this.remote_target=o.uri,this.route_set=i.getHeaders("record-route"),this.invite_seqnum=i.cseq,this.local_seqnum=i.cseq):"UAC"===s&&(this.id={call_id:i.call_id,local_tag:i.from_tag,remote_tag:i.to_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this.state=n,this.invite_seqnum=i.cseq,this.local_seqnum=i.cseq,this.local_uri=i.parseHeader("from").uri,this.pracked=[],this.remote_uri=i.parseHeader("to").uri,this.remote_target=o.uri,this.route_set=i.getHeaders("record-route").reverse()),this.logger=t.ua.getLogger("sip.dialog",this.id.toString()),this.owner=t,t.ua.dialogs[this.id.toString()]=this,this.logger.log("new "+s+" dialog created with status "+(this.state===r.STATUS_EARLY?"EARLY":"CONFIRMED")),t.emit("dialog",this)}).prototype={update:function(e,t){this.state=r.STATUS_CONFIRMED,this.logger.log("dialog "+this.id.toString()+" changed to CONFIRMED state"),"UAC"===t&&(this.route_set=e.getHeaders("record-route").reverse())},terminate:function(){this.logger.log("dialog "+this.id.toString()+" deleted"),this.sessionDescriptionHandler&&this.state!==r.STATUS_CONFIRMED&&this.sessionDescriptionHandler.close(),delete this.owner.ua.dialogs[this.id.toString()]},createRequest:function(t,i,s){var r,n;return i=(i||[]).slice(),this.local_seqnum||(this.local_seqnum=Math.floor(1e4*Math.random())),r=t===e.C.CANCEL||t===e.C.ACK?this.invite_seqnum:this.local_seqnum+=1,n=new e.OutgoingRequest(t,this.remote_target,this.owner.ua,{cseq:r,call_id:this.id.call_id,from_uri:this.local_uri,from_tag:this.id.local_tag,to_uri:this.remote_uri,to_tag:this.id.remote_tag,route_set:this.route_set},i,s),n.dialog=this,n},checkInDialogRequest:function(t){var i=this;if(this.remote_seqnum){if(t.cseqthis.remote_seqnum){var s=1+(10*Math.random()|0);return t.reply(500,null,["Retry-After:"+s]),this.remote_seqnum=t.cseq,!1}this.uas_pending_reply=!0,t.server_transaction.on("stateChanged",function t(){this.state!==e.Transactions.C.STATUS_ACCEPTED&&this.state!==e.Transactions.C.STATUS_COMPLETED&&this.state!==e.Transactions.C.STATUS_TERMINATED||(this.removeListener("stateChanged",t),i.uas_pending_reply=!1)})}t.hasHeader("contact")&&t.server_transaction.on("stateChanged",function(){this.state===e.Transactions.C.STATUS_ACCEPTED&&(i.remote_target=t.parseHeader("contact").uri)});break;case e.C.NOTIFY:t.hasHeader("contact")&&t.server_transaction.on("stateChanged",function(){this.state===e.Transactions.C.STATUS_COMPLETED&&(i.remote_target=t.parseHeader("contact").uri)})}return t.cseq>this.remote_seqnum&&(this.remote_seqnum=t.cseq),!0},sendRequest:function(e,t,i){var r=((i=i||{}).extraHeaders||[]).slice(),n=null;i.body&&(i.body.body?n=i.body:((n={}).body=i.body,i.contentType&&(n.contentType=i.contentType)));var o=this.createRequest(t,r,n);return new s(this,e,o).send(),o},receiveRequest:function(e){this.checkInDialogRequest(e)&&this.owner.receiveRequest(e)}},t.C=r,e.Dialog=t}},function(e,t,i){"use strict";e.exports=function(e){var t;return t=function(e,t,i){this.dialog=e,this.applicant=t,this.request=i,this.reattempt=!1,this.reattemptTimer=null},t.prototype={send:function(){var t=this,i=new e.RequestSender(this,this.dialog.owner.ua);i.send(),this.request.method===e.C.INVITE&&i.clientTransaction.state!==e.Transactions.C.STATUS_TERMINATED&&(this.dialog.uac_pending_reply=!0,i.clientTransaction.on("stateChanged",function i(){this.state!==e.Transactions.C.STATUS_ACCEPTED&&this.state!==e.Transactions.C.STATUS_COMPLETED&&this.state!==e.Transactions.C.STATUS_TERMINATED||(this.removeListener("stateChanged",i),t.dialog.uac_pending_reply=!1)}))},onRequestTimeout:function(){this.applicant.onRequestTimeout()},onTransportError:function(){this.applicant.onTransportError()},receiveResponse:function(t){var i=this;408===t.status_code||481===t.status_code?this.applicant.onDialogError(t):t.method===e.C.INVITE&&491===t.status_code?this.reattempt?this.applicant.receiveResponse(t):(this.request.cseq.value=this.dialog.local_seqnum+=1,this.reattemptTimer=e.Timers.setTimeout(function(){i.applicant.owner.status!==e.Session.C.STATUS_TERMINATED&&(i.reattempt=!0,i.request_sender.send())},this.getReattemptTimeout())):this.applicant.receiveResponse(t)}},t}},function(e,t,i){"use strict";e.exports=function(e){var t;(t=function(t,i){this.logger=i.getLogger("sip.requestsender"),this.ua=i,this.applicant=t,this.method=t.request.method,this.request=t.request,this.credentials=null,this.challenged=!1,this.staled=!1,i.status!==e.UA.C.STATUS_USER_CLOSED||this.method===e.C.BYE&&this.method===e.C.ACK||this.onTransportError()}).prototype={send:function(){switch(this.method){case"INVITE":this.clientTransaction=new e.Transactions.InviteClientTransaction(this,this.request,this.ua.transport);break;case"ACK":this.clientTransaction=new e.Transactions.AckClientTransaction(this,this.request,this.ua.transport);break;default:this.clientTransaction=new e.Transactions.NonInviteClientTransaction(this,this.request,this.ua.transport)}return this.clientTransaction.send(),this.clientTransaction},onRequestTimeout:function(){this.applicant.onRequestTimeout()},onTransportError:function(){this.applicant.onTransportError()},receiveResponse:function(t){var i,s,r,n=t.status_code;if(401===n||407===n){if(401===t.status_code?(s=t.parseHeader("www-authenticate"),r="authorization"):(s=t.parseHeader("proxy-authenticate"),r="proxy-authorization"),!s)return this.logger.warn(t.status_code+" with wrong or missing challenge, cannot authenticate"),void this.applicant.receiveResponse(t);if(!this.challenged||!this.staled&&!0===s.stale){if(this.credentials||(this.credentials=this.ua.configuration.authenticationFactory(this.ua)),!this.credentials.authenticate(this.request,s))return void this.applicant.receiveResponse(t);this.challenged=!0,s.stale&&(this.staled=!0),t.method===e.C.REGISTER?i=this.applicant.cseq+=1:this.request.dialog?i=this.request.dialog.local_seqnum+=1:(i=this.request.cseq+1,this.request.cseq=i),this.request.setHeader("cseq",i+" "+this.method),this.request.setHeader(r,this.credentials.toString()),this.send()}else this.applicant.receiveResponse(t)}else this.applicant.receiveResponse(t)}},e.RequestSender=t}},function(e,t,i){"use strict";e.exports=function(e){var t;(t=function(t){var i={};this.registrar=t.configuration.registrarServer,this.expires=t.configuration.registerExpires,this.contact=t.contact.toString(),this.contact+=";reg-id=1",this.contact+=';+sip.instance=""',this.call_id=e.Utils.createRandomToken(22),this.cseq=Math.floor(1e4*Math.random()),this.to_uri=t.configuration.uri,i.to_uri=this.to_uri,i.to_displayName=t.configuration.displayName,i.call_id=this.call_id,i.cseq=this.cseq,e.Utils.augment(this,e.ClientContext,[t,"REGISTER",this.registrar,{params:i}]),this.registrationTimer=null,this.registrationExpiredTimer=null,this.registered=!1,this.logger=t.getLogger("sip.registercontext")}).prototype={register:function(t){var i,s=this;this.options=t||{},(i=(this.options.extraHeaders||[]).slice()).push("Contact: "+this.contact+";expires="+this.expires),i.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.closeHeaders=this.options.closeWithHeaders?(this.options.extraHeaders||[]).slice():[],this.receiveResponse=function(t){var i,r,n,o=t.getHeaders("contact").length;if(t.cseq===this.cseq)switch(null!==this.registrationTimer&&(e.Timers.clearTimeout(this.registrationTimer),this.registrationTimer=null),!0){case/^1[0-9]{2}$/.test(t.status_code):this.emit("progress",t);break;case/^2[0-9]{2}$/.test(t.status_code):if(this.emit("accepted",t),t.hasHeader("expires")&&(r=t.getHeader("expires")),null!==this.registrationExpiredTimer&&(e.Timers.clearTimeout(this.registrationExpiredTimer),this.registrationExpiredTimer=null),!o){this.logger.warn("no Contact header in response to REGISTER, response ignored");break}for(;o--;){if((i=t.parseHeader("contact",o)).uri.user===this.ua.contact.uri.user){r=i.getParam("expires");break}i=null}if(!i){this.logger.warn("no Contact header pointing to us, response ignored");break}r||(r=this.expires),this.registrationTimer=e.Timers.setTimeout(function(){s.registrationTimer=null,s.register(s.options)},1e3*r-3e3),this.registrationExpiredTimer=e.Timers.setTimeout(function(){s.logger.warn("registration expired"),s.registered&&s.unregistered(null,e.C.causes.EXPIRES)},1e3*r),i.hasParam("temp-gruu")&&(this.ua.contact.temp_gruu=e.URI.parse(i.getParam("temp-gruu").replace(/"/g,""))),i.hasParam("pub-gruu")&&(this.ua.contact.pub_gruu=e.URI.parse(i.getParam("pub-gruu").replace(/"/g,""))),this.registered=!0,this.emit("registered",t||null);break;case/^423$/.test(t.status_code):t.hasHeader("min-expires")?(this.expires=t.getHeader("min-expires"),this.register(this.options)):(this.logger.warn("423 response received for REGISTER without Min-Expires"),this.registrationFailure(t,e.C.causes.SIP_FAILURE_CODE));break;default:n=e.Utils.sipErrorCause(t.status_code),this.registrationFailure(t,n)}},this.onRequestTimeout=function(){this.registrationFailure(null,e.C.causes.REQUEST_TIMEOUT)},this.onTransportError=function(){this.registrationFailure(null,e.C.causes.CONNECTION_ERROR)},this.cseq++,this.request.cseq=this.cseq,this.request.setHeader("cseq",this.cseq+" REGISTER"),this.request.extraHeaders=i,this.send()},registrationFailure:function(e,t){this.emit("failed",e||null,t||null)},onTransportClosed:function(){this.registered_before=this.registered,null!==this.registrationTimer&&(e.Timers.clearTimeout(this.registrationTimer),this.registrationTimer=null),null!==this.registrationExpiredTimer&&(e.Timers.clearTimeout(this.registrationExpiredTimer),this.registrationExpiredTimer=null),this.registered&&this.unregistered(null,e.C.causes.CONNECTION_ERROR)},onTransportConnected:function(){this.register(this.options)},close:function(){var e={all:!1,extraHeaders:this.closeHeaders};this.registered_before=this.registered,this.registered&&this.unregister(e)},unregister:function(t){var i;t=t||{},this.registered||t.all||this.logger.warn("Already unregistered, but sending an unregister anyways."),i=(t.extraHeaders||[]).slice(),this.registered=!1,null!==this.registrationTimer&&(e.Timers.clearTimeout(this.registrationTimer),this.registrationTimer=null),t.all?(i.push("Contact: *"),i.push("Expires: 0")):i.push("Contact: "+this.contact+";expires=0"),this.receiveResponse=function(t){var i;switch(!0){case/^1[0-9]{2}$/.test(t.status_code):this.emit("progress",t);break;case/^2[0-9]{2}$/.test(t.status_code):this.emit("accepted",t),null!==this.registrationExpiredTimer&&(e.Timers.clearTimeout(this.registrationExpiredTimer),this.registrationExpiredTimer=null),this.unregistered(t);break;default:i=e.Utils.sipErrorCause(t.status_code),this.unregistered(t,i)}},this.onRequestTimeout=function(){},this.onTransportError=function(){},this.cseq++,this.request.cseq=this.cseq,this.request.setHeader("cseq",this.cseq+" REGISTER"),this.request.extraHeaders=i,this.send()},unregistered:function(e,t){this.registered=!1,this.emit("unregistered",e||null,t||null)}},e.RegisterContext=t}},function(e,t,i){"use strict";e.exports=function(e){var t=function(e,t){};return t.prototype=Object.create(e.prototype,{close:{value:function(){}},getDescription:{value:function(e,t){}},hasDescription:{value:function(e){}},holdModifier:{value:function(e){}},setDescription:{value:function(e,t,i){}}}),t}},function(e,t,i){"use strict";e.exports=function(e){var t;((t=function(t,i,s,r){var n=s;if(void 0===s)throw new TypeError("Not enough arguments");if(this.ua=t,this.logger=t.getLogger("sip.clientcontext"),this.method=i,!(s=t.normalizeTarget(s)))throw new TypeError("Invalid target: "+n);(r=Object.create(r||Object.prototype)).extraHeaders=(r.extraHeaders||[]).slice(),this.request=new e.OutgoingRequest(this.method,s,this.ua,r.params,r.extraHeaders),r.body&&(this.body={},this.body.body=r.body,r.contentType&&(this.body.contentType=r.contentType),this.request.body=this.body),this.localIdentity=this.request.from,this.remoteIdentity=this.request.to,this.data={}}).prototype=Object.create(e.EventEmitter.prototype)).send=function(){return new e.RequestSender(this,this.ua).send(),this},t.prototype.cancel=function(t){(t=t||{}).extraHeaders=(t.extraHeaders||[]).slice();var i=e.Utils.getCancelReason(t.status_code,t.reason_phrase);this.request.cancel(i,t.extraHeaders),this.emit("cancel")},t.prototype.receiveResponse=function(t){var i=e.Utils.getReasonPhrase(t.status_code);switch(!0){case/^1[0-9]{2}$/.test(t.status_code):this.emit("progress",t,i);break;case/^2[0-9]{2}$/.test(t.status_code):this.ua.applicants[this]&&delete this.ua.applicants[this],this.emit("accepted",t,i);break;default:this.ua.applicants[this]&&delete this.ua.applicants[this],this.emit("rejected",t,i),this.emit("failed",t,i)}},t.prototype.onRequestTimeout=function(){this.emit("failed",null,e.C.causes.REQUEST_TIMEOUT)},t.prototype.onTransportError=function(){this.emit("failed",null,e.C.causes.CONNECTION_ERROR)},e.ClientContext=t}},function(e,t,i){"use strict";e.exports=function(e){var t;((t=function(t,i){this.ua=t,this.logger=t.getLogger("sip.servercontext"),this.request=i,i.method===e.C.INVITE?this.transaction=new e.Transactions.InviteServerTransaction(i,t):this.transaction=new e.Transactions.NonInviteServerTransaction(i,t),i.body&&(this.body=i.body),i.hasHeader("Content-Type")&&(this.contentType=i.getHeader("Content-Type")),this.method=i.method,this.data={},this.localIdentity=i.to,this.remoteIdentity=i.from}).prototype=Object.create(e.EventEmitter.prototype)).progress=function(e){return(e=Object.create(e||Object.prototype)).statusCode||(e.statusCode=180),e.minCode=100,e.maxCode=199,e.events=["progress"],this.reply(e)},t.prototype.accept=function(e){return(e=Object.create(e||Object.prototype)).statusCode||(e.statusCode=200),e.minCode=200,e.maxCode=299,e.events=["accepted"],this.reply(e)},t.prototype.reject=function(e){return(e=Object.create(e||Object.prototype)).statusCode||(e.statusCode=480),e.minCode=300,e.maxCode=699,e.events=["rejected","failed"],this.reply(e)},t.prototype.reply=function(t){var i,s=(t=t||{}).statusCode||100,r=t.minCode||100,n=t.maxCode||699,o=e.Utils.getReasonPhrase(s,t.reasonPhrase),a=t.extraHeaders||[],c=t.body,h=t.events||[];if(sn)throw new TypeError("Invalid statusCode: "+s);return i=this.request.reply(s,o,a,c),h.forEach(function(e){this.emit(e,i,o)},this),this},t.prototype.onRequestTimeout=function(){this.emit("failed",null,e.C.causes.REQUEST_TIMEOUT)},t.prototype.onTransportError=function(){this.emit("failed",null,e.C.causes.CONNECTION_ERROR)},e.ServerContext=t}},function(e,t,i){"use strict";e.exports=function(e){var t,s,r,n,o,a=i(24)(e),c={STATUS_NULL:0,STATUS_INVITE_SENT:1,STATUS_1XX_RECEIVED:2,STATUS_INVITE_RECEIVED:3,STATUS_WAITING_FOR_ANSWER:4,STATUS_ANSWERED:5,STATUS_WAITING_FOR_PRACK:6,STATUS_WAITING_FOR_ACK:7,STATUS_CANCELED:8,STATUS_TERMINATED:9,STATUS_ANSWERED_WAITING_FOR_PRACK:10,STATUS_EARLY_MEDIA:11,STATUS_CONFIRMED:12};(t=function(t){if(this.status=c.STATUS_NULL,this.dialog=null,this.pendingReinvite=!1,this.earlyDialogs={},!t)throw new e.Exceptions.SessionDescriptionHandlerMissing("A session description handler is required for the session to function");this.sessionDescriptionHandlerFactory=t,this.hasOffer=!1,this.hasAnswer=!1,this.timers={ackTimer:null,expiresTimer:null,invite2xxTimer:null,userNoAnswerTimer:null,rel1xxTimer:null,prackTimer:null},this.startTime=null,this.endTime=null,this.tones=null,this.local_hold=!1,this.disableRenegotiation=!1,this.early_sdp=null,this.rel100=e.C.supported.UNSUPPORTED}).prototype={dtmf:function(t,i){var s=[],r=this;if(i=i||{},void 0===t)throw new TypeError("Not enough arguments");if(this.status!==c.STATUS_CONFIRMED&&this.status!==c.STATUS_WAITING_FOR_ACK)throw new e.Exceptions.InvalidStateError(this.status);if("string"!=typeof t&&"number"!=typeof t||!t.toString().match(/^[0-9A-D#*,]+$/i))throw new TypeError("Invalid tones: "+t);for(t=t.toString().split("");t.length>0;)s.push(new a(this,t.shift(),i));if(this.tones)return this.tones=this.tones.concat(s),this;return this.tones=s,function t(){var s,n;if(r.status===c.STATUS_TERMINATED||!r.tones||0===r.tones.length)return r.tones=null,this;(s=r.tones.shift()).on("failed",function(){r.tones=null}),s.send(i),n=s.duration+s.interToneGap,e.Timers.setTimeout(t,n)}(),this},bye:function(t){var i=(t=Object.create(t||Object.prototype)).statusCode;if(this.status===c.STATUS_TERMINATED)return this.logger.error("Error: Attempted to send BYE in a terminated session."),this;if(this.logger.log("terminating Session"),i&&(i<200||i>=700))throw new TypeError("Invalid statusCode: "+i);return t.receiveResponse=function(){},this.sendRequest(e.C.BYE,t).terminated()},refer:function(t,i){if(i=i||{},this.status!==c.STATUS_CONFIRMED)throw new e.Exceptions.InvalidStateError(this.status);this.referContext=new e.ReferClientContext(this.ua,this,t,i),this.emit("referRequested",this.referContext),this.referContext.refer()},sendRequest:function(t,i){i=i||{};var s=this,r=new e.OutgoingRequest(t,this.dialog.remote_target,this.ua,{cseq:i.cseq||(this.dialog.local_seqnum+=1),call_id:this.dialog.id.call_id,from_uri:this.dialog.local_uri,from_tag:this.dialog.id.local_tag,to_uri:this.dialog.remote_uri,to_tag:this.dialog.id.remote_tag,route_set:this.dialog.route_set,statusCode:i.statusCode,reasonPhrase:i.reasonPhrase},i.extraHeaders||[],i.body);return new e.RequestSender({request:r,onRequestTimeout:function(){s.onRequestTimeout()},onTransportError:function(){s.onTransportError()},receiveResponse:i.receiveResponse||function(e){s.receiveNonInviteResponse(e)}},this.ua).send(),this.emit(t.toLowerCase(),r),this},close:function(){var t;if(this.status===c.STATUS_TERMINATED)return this;this.logger.log("closing INVITE session "+this.id),this.sessionDescriptionHandler&&this.sessionDescriptionHandler.close();for(t in this.timers)e.Timers.clearTimeout(this.timers[t]);this.dialog&&(this.dialog.terminate(),delete this.dialog);for(t in this.earlyDialogs)this.earlyDialogs[t].terminate(),delete this.earlyDialogs[t];return this.status=c.STATUS_TERMINATED,delete this.ua.sessions[this.id],this},createDialog:function(t,i,s){var r,n,o=t["UAS"===i?"to_tag":"from_tag"],a=t["UAS"===i?"from_tag":"to_tag"],c=t.call_id+o+a;if(n=this.earlyDialogs[c],s)return!!n||((n=new e.Dialog(this,t,i,e.Dialog.C.STATUS_EARLY)).error?(this.logger.error(n.error),this.failed(t,e.C.causes.INTERNAL_ERROR),!1):(this.earlyDialogs[c]=n,!0));if(n){n.update(t,i),this.dialog=n,delete this.earlyDialogs[c];for(var h in this.earlyDialogs)this.earlyDialogs[h].terminate(),delete this.earlyDialogs[h];return!0}return(r=new e.Dialog(this,t,i)).error?(this.logger.error(r.error),this.failed(t,e.C.causes.INTERNAL_ERROR),!1):(this.to_tag=t.to_tag,this.dialog=r,!0)},hold:function(t,i){if(this.status!==c.STATUS_WAITING_FOR_ACK&&this.status!==c.STATUS_CONFIRMED)throw new e.Exceptions.InvalidStateError(this.status);this.local_hold?this.logger.log("Session is already on hold, cannot put it on hold again"):((t=t||{}).modifiers=i||[],t.modifiers.push(this.sessionDescriptionHandler.holdModifier),this.local_hold=!0,this.sendReinvite(t))},unhold:function(t,i){if(this.status!==c.STATUS_WAITING_FOR_ACK&&this.status!==c.STATUS_CONFIRMED)throw new e.Exceptions.InvalidStateError(this.status);this.local_hold?(t=t||{},i&&(t.modifiers=i),this.local_hold=!1,this.sendReinvite(t)):this.logger.log("Session is not on hold, cannot unhold it")},reinvite:function(e,t){return e=e||{},t&&(e.modifiers=t),this.sendReinvite(e)},receiveReinvite:function(t){var i,s=this;if(s.emit("reinvite",this),"0"!==t.getHeader("Content-Length")||t.getHeader("Content-Type")){if(!this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type")))return t.reply(415),void this.emit("reinviteFailed",s);i=this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler,this.sessionDescriptionHandlerOptions,this.modifiers))}else i=this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions,this.modifiers);var r=this.receiveRequest;this.receiveRequest=function(t){t.method===e.C.ACK&&this.status===c.STATUS_WAITING_FOR_ACK&&this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type"))?(this.hasAnswer=!0,this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(function(){e.Timers.clearTimeout(this.timers.ackTimer),e.Timers.clearTimeout(this.timers.invite2xxTimer),this.status=c.STATUS_CONFIRMED,this.emit("confirmed",t)}.bind(this))):r.call(this,t)}.bind(this),i.catch(function(i){var r;i instanceof e.Exceptions.GetDescriptionError?r=500:i instanceof e.Exceptions.RenegotiationError?(s.emit("renegotiationError",i),s.logger.warn(i),r=488):(s.logger.error(i),r=488),t.reply(r),s.emit("reinviteFailed",s)}).then(function(e){var i=["Contact: "+s.contact];t.reply(200,null,i,e,function(){s.status=c.STATUS_WAITING_FOR_ACK,s.setACKTimer(),s.emit("reinviteAccepted",s)})})},sendReinvite:function(t){if(this.pendingReinvite)this.logger.warn("Reinvite in progress. Please wait until complete, then try again.");else{this.pendingReinvite=!0,(t=t||{}).modifiers=t.modifiers||[];var i=this,s=(t.extraHeaders||[]).slice();s.push("Contact: "+this.contact),s.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.sessionDescriptionHandler.getDescription(t.sessionDescriptionHandlerOptions,t.modifiers).then(function(t){i.sendRequest(e.C.INVITE,{extraHeaders:s,body:t,receiveResponse:i.receiveReinviteResponse.bind(i)})}).catch(function(t){if(t instanceof e.Exceptions.RenegotiationError)return i.pendingReinvite=!1,i.emit("renegotiationError",t),i.logger.warn("Renegotiation Error"),void i.logger.warn(t);i.logger.error("sessionDescriptionHandler error"),i.logger.error(t)})}},receiveRequest:function(t){switch(t.method){case e.C.BYE:t.reply(200),this.status===c.STATUS_CONFIRMED&&(this.emit("bye",t),this.terminated(t,e.C.causes.BYE));break;case e.C.INVITE:this.status===c.STATUS_CONFIRMED&&(this.logger.log("re-INVITE received"),this.receiveReinvite(t));break;case e.C.INFO:if(this.status===c.STATUS_CONFIRMED||this.status===c.STATUS_WAITING_FOR_ACK){if(this.onInfo)return this.onInfo(t);var i,s,r,n=t.getHeader("content-type"),o=/^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/,h=/^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;n&&(n.match(/^application\/dtmf-relay/i)?(t.body&&2===(i=t.body.split("\r\n",2)).length&&(o.test(i[0])&&(s=i[0].replace(o,"$2")),h.test(i[1])&&(r=parseInt(i[1].replace(h,"$2"),10))),new a(this,s,{duration:r}).init_incoming(t)):t.reply(415,null,["Accept: application/dtmf-relay"]))}break;case e.C.REFER:if(this.status===c.STATUS_CONFIRMED){this.logger.log("REFER received"),this.referContext=new e.ReferServerContext(this.ua,t);if(this.listeners("referRequested").length)this.emit("referRequested",this.referContext);else{this.logger.log("No referRequested listeners, automatically accepting and following the refer");var u={followRefer:!0};this.passedOptions&&(u.inviteOptions=this.passedOptions),this.referContext.accept(u,this.modifiers)}}break;case e.C.NOTIFY:if(this.referContext&&this.referContext instanceof e.ReferClientContext&&t.hasHeader("event")&&"refer"===t.getHeader("event"))return void this.referContext.receiveNotify(t);t.reply(200,"OK"),this.emit("notify",t)}},receiveReinviteResponse:function(t){var i=this;if(this.status!==c.STATUS_TERMINATED)switch(!0){case/^1[0-9]{2}$/.test(t.status_code):break;case/^2[0-9]{2}$/.test(t.status_code):if(this.status=c.STATUS_CONFIRMED,this.emit("ack",t.transaction.sendACK()),this.pendingReinvite=!1,e.Timers.clearTimeout(i.timers.invite2xxTimer),!this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type"))){this.logger.error("2XX response received to re-invite but did not have a description"),this.emit("renegotiationError",new e.Exceptions.RenegotiationError("2XX response received to re-invite but did not have a description"));break}this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).catch(function(t){i.logger.error("Could not set the description in 2XX response"),i.logger.error(t),i.emit("renegotiationError",t),i.sendRequest(e.C.BYE,{extraHeaders:[e.Utils.getReasonHeaderValue(488,"Not Acceptable Here")]})});break;default:this.disableRenegotiation=!0,this.pendingReinvite=!1,this.logger.log("Received a non 1XX or 2XX response to a re-invite"),this.emit("renegotiationError",new e.Exceptions.RenegotiationError("Invalid response to a re-invite"))}},acceptAndTerminate:function(t,i,s){var r=[];return i&&r.push("Reason: "+e.Utils.getReasonHeaderValue(i,s)),(this.dialog||this.createDialog(t,"UAC"))&&(this.emit("ack",t.transaction.sendACK()),this.sendRequest(e.C.BYE,{extraHeaders:r})),this},setInvite2xxTimer:function(t,i){var s=this,r=e.Timers.T1;this.timers.invite2xxTimer=e.Timers.setTimeout(function n(){if(s.status===c.STATUS_WAITING_FOR_ACK){s.logger.log("no ACK received, attempting to retransmit OK");var o=["Contact: "+s.contact];t.reply(200,null,o,i),r=Math.min(2*r,e.Timers.T2),s.timers.invite2xxTimer=e.Timers.setTimeout(n,r)}},r)},setACKTimer:function(){var t=this;this.timers.ackTimer=e.Timers.setTimeout(function(){t.status===c.STATUS_WAITING_FOR_ACK&&(t.logger.log("no ACK received for an extended period of time, terminating the call"),e.Timers.clearTimeout(t.timers.invite2xxTimer),t.sendRequest(e.C.BYE),t.terminated(null,e.C.causes.NO_ACK))},e.Timers.TIMER_H)},onTransportError:function(){this.status!==c.STATUS_CONFIRMED&&this.status!==c.STATUS_TERMINATED&&this.failed(null,e.C.causes.CONNECTION_ERROR)},onRequestTimeout:function(){this.status===c.STATUS_CONFIRMED?this.terminated(null,e.C.causes.REQUEST_TIMEOUT):this.status!==c.STATUS_TERMINATED&&(this.failed(null,e.C.causes.REQUEST_TIMEOUT),this.terminated(null,e.C.causes.REQUEST_TIMEOUT))},onDialogError:function(t){this.status===c.STATUS_CONFIRMED?this.terminated(t,e.C.causes.DIALOG_ERROR):this.status!==c.STATUS_TERMINATED&&(this.failed(t,e.C.causes.DIALOG_ERROR),this.terminated(t,e.C.causes.DIALOG_ERROR))},failed:function(e,t){return this.status===c.STATUS_TERMINATED?this:(this.emit("failed",e||null,t||null),this)},rejected:function(e,t){return this.emit("rejected",e||null,t||null),this},canceled:function(){return this.emit("cancel"),this},accepted:function(t,i){return i=e.Utils.getReasonPhrase(t&&t.status_code,i),this.startTime=new Date,this.replacee&&(this.replacee.emit("replaced",this),this.replacee.terminate()),this.emit("accepted",t,i),this},terminated:function(e,t){return this.status===c.STATUS_TERMINATED?this:(this.endTime=new Date,this.close(),this.emit("terminated",e||null,t||null),this)},connecting:function(e){return this.emit("connecting",{request:e}),this}},t.C=c,e.Session=t,(s=function(t,i){function s(e,t){i.hasHeader(e)&&i.getHeader(e).toLowerCase().indexOf("100rel")>=0&&(n.rel100=t)}var r,n=this,o=i.getHeader("Content-Type"),a=i.parseHeader("Content-Disposition");if(e.Utils.augment(this,e.ServerContext,[t,i]),e.Utils.augment(this,e.Session,[t.configuration.sessionDescriptionHandlerFactory]),a&&"render"===a.type&&(this.renderbody=i.body,this.rendertype=o),this.status=c.STATUS_INVITE_RECEIVED,this.from_tag=i.from_tag,this.id=i.call_id+this.from_tag,this.request=i,this.contact=this.ua.contact.toString(),this.receiveNonInviteResponse=function(){},this.logger=t.getLogger("sip.inviteservercontext",this.id),this.ua.sessions[this.id]=this,i.hasHeader("expires")&&(r=1e3*i.getHeader("expires")),s("require",e.C.supported.REQUIRED),s("supported",e.C.supported.SUPPORTED),i.to_tag=e.Utils.newTag(),this.createDialog(i,"UAS",!0)){var h={extraHeaders:["Contact: "+n.contact]};n.rel100!==e.C.supported.REQUIRED&&n.progress(h),n.status=c.STATUS_WAITING_FOR_ANSWER,n.timers.userNoAnswerTimer=e.Timers.setTimeout(function(){i.reply(408),n.failed(i,e.C.causes.NO_ANSWER),n.terminated(i,e.C.causes.NO_ANSWER)},n.ua.configuration.noAnswerTimeout),r&&(n.timers.expiresTimer=e.Timers.setTimeout(function(){n.status===c.STATUS_WAITING_FOR_ANSWER&&(i.reply(487),n.failed(i,e.C.causes.EXPIRES),n.terminated(i,e.C.causes.EXPIRES))},r))}else i.reply(500,"Missing Contact header field")}).prototype={reject:function(t){if(this.status===c.STATUS_TERMINATED)throw new e.Exceptions.InvalidStateError(this.status);return this.logger.log("rejecting RTCSession"),e.ServerContext.prototype.reject.call(this,t),this.terminated()},terminate:function(t){var i,s=((t=t||{}).extraHeaders||[]).slice(),r=t.body,n=this;return this.status===c.STATUS_WAITING_FOR_ACK&&this.request.server_transaction.state!==e.Transactions.C.STATUS_TERMINATED?(i=this.dialog,this.receiveRequest=function(t){t.method===e.C.ACK&&(this.sendRequest(e.C.BYE,{extraHeaders:s,body:r}),i.terminate())},this.request.server_transaction.on("stateChanged",function(){this.state===e.Transactions.C.STATUS_TERMINATED&&this.dialog&&(this.request=new e.OutgoingRequest(e.C.BYE,this.dialog.remote_target,this.ua,{cseq:this.dialog.local_seqnum+=1,call_id:this.dialog.id.call_id,from_uri:this.dialog.local_uri,from_tag:this.dialog.id.local_tag,to_uri:this.dialog.remote_uri,to_tag:this.dialog.id.remote_tag,route_set:this.dialog.route_set},s,r),new e.RequestSender({request:this.request,onRequestTimeout:function(){n.onRequestTimeout()},onTransportError:function(){n.onTransportError()},receiveResponse:function(){}},this.ua).send(),i.terminate())}),this.emit("bye",this.request),this.terminated(),this.dialog=i,this.ua.dialogs[i.id.toString()]=i):this.status===c.STATUS_CONFIRMED?this.bye(t):this.reject(t),this},progress:function(t){function i(){r=t.statusCode||183,this.status=c.STATUS_WAITING_FOR_PRACK,o.push("Contact: "+this.contact),o.push("Require: 100rel"),o.push("RSeq: "+Math.floor(1e4*Math.random())),this.sessionDescriptionHandler.getDescription(t.sessionDescriptionHandlerOptions,t.modifiers).then(function(t){if(!this.isCanceled&&this.status!==c.STATUS_TERMINATED){this.early_sdp=t.body,this[this.hasOffer?"hasAnswer":"hasOffer"]=!0;var i=e.Timers.T1;this.timers.rel1xxTimer=e.Timers.setTimeout(function s(){this.request.reply(r,null,o,t),i*=2,this.timers.rel1xxTimer=e.Timers.setTimeout(s.bind(this),i)}.bind(this),i),this.timers.prackTimer=e.Timers.setTimeout(function(){this.status===c.STATUS_WAITING_FOR_PRACK&&(this.logger.log("no PRACK received, rejecting the call"),e.Timers.clearTimeout(this.timers.rel1xxTimer),this.request.reply(504),this.terminated(null,e.C.causes.NO_PRACK))}.bind(this),64*e.Timers.T1),s=this.request.reply(r,n,o,t),this.emit("progress",s,n)}}.bind(this),function(){this.request.reply(480),this.failed(null,e.C.causes.WEBRTC_ERROR),this.terminated(null,e.C.causes.WEBRTC_ERROR)}.bind(this))}var s,r=(t=t||{}).statusCode||180,n=t.reasonPhrase,o=(t.extraHeaders||[]).slice(),a=t.body;if(r<100||r>199)throw new TypeError("Invalid statusCode: "+r);return this.isCanceled||this.status===c.STATUS_TERMINATED?this:(100!==t.statusCode&&(this.rel100===e.C.supported.REQUIRED||this.rel100===e.C.supported.SUPPORTED&&t.rel100||this.rel100===e.C.supported.SUPPORTED&&this.ua.configuration.rel100===e.C.supported.REQUIRED)?(this.sessionDescriptionHandler=this.setupSessionDescriptionHandler(),this.sessionDescriptionHandler.hasDescription(this.request.getHeader("Content-Type"))?(this.hasOffer=!0,this.sessionDescriptionHandler.setDescription(this.request.body,t.sessionDescriptionHandlerOptions,t.modifiers).then(i.apply(this)).catch(function(t){this.logger.warn("invalid description"),this.logger.warn(t),this.failed(null,e.C.causes.WEBRTC_ERROR),this.terminated(null,e.C.causes.WEBRTC_ERROR)}.bind(this))):i.apply(this)):function(){s=this.request.reply(r,n,o,a),this.emit("progress",s,n)}.apply(this),this)},accept:function(t){t=t||{},this.onInfo=t.onInfo;var i=this,s=this.request,r=(t.extraHeaders||[]).slice(),n=function(t){var n;r.push("Contact: "+i.contact),r.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),i.hasOffer?i.hasAnswer=!0:i.hasOffer=!0,n=s.reply(200,null,r,t,function(){i.status=c.STATUS_WAITING_FOR_ACK,i.setInvite2xxTimer(s,t),i.setACKTimer()},function(){i.failed(null,e.C.causes.CONNECTION_ERROR),i.terminated(null,e.C.causes.CONNECTION_ERROR)}),i.status!==c.STATUS_TERMINATED&&i.accepted(n,e.Utils.getReasonPhrase(200))},o=function(){i.status!==c.STATUS_TERMINATED&&(i.request.reply(480),i.failed(null,e.C.causes.WEBRTC_ERROR),i.terminated(null,e.C.causes.WEBRTC_ERROR))};if(this.status===c.STATUS_WAITING_FOR_PRACK)return this.status=c.STATUS_ANSWERED_WAITING_FOR_PRACK,this;if(this.status===c.STATUS_WAITING_FOR_ANSWER)this.status=c.STATUS_ANSWERED;else if(this.status!==c.STATUS_EARLY_MEDIA)throw new e.Exceptions.InvalidStateError(this.status);if(!this.createDialog(s,"UAS"))return s.reply(500,"Missing Contact header field"),this;if(e.Timers.clearTimeout(this.timers.userNoAnswerTimer),this.status===c.STATUS_EARLY_MEDIA)n({});else if(this.sessionDescriptionHandler=this.setupSessionDescriptionHandler(),"0"!==this.request.getHeader("Content-Length")||this.request.getHeader("Content-Type")){if(!this.sessionDescriptionHandler.hasDescription(this.request.getHeader("Content-Type")))return void this.request.reply(415);this.hasOffer=!0,this.sessionDescriptionHandler.setDescription(this.request.body,t.sessionDescriptionHandlerOptions,t.modifiers).then(function(){return this.sessionDescriptionHandler.getDescription(t.sessionDescriptionHandlerOptions,t.modifiers)}.bind(this)).catch(o).then(n)}else this.sessionDescriptionHandler.getDescription(t.sessionDescriptionHandlerOptions,t.modifiers).catch(o).then(n);return this},receiveRequest:function(i){function s(){var t,s;e.Timers.clearTimeout(this.timers.ackTimer),e.Timers.clearTimeout(this.timers.invite2xxTimer),this.status=c.STATUS_CONFIRMED,t=i.getHeader("Content-Type"),(s=i.getHeader("Content-Disposition"))&&"render"===s.type&&(this.renderbody=i.body,this.rendertype=t),this.emit("confirmed",i)}switch(i.method){case e.C.CANCEL:this.status!==c.STATUS_WAITING_FOR_ANSWER&&this.status!==c.STATUS_WAITING_FOR_PRACK&&this.status!==c.STATUS_ANSWERED_WAITING_FOR_PRACK&&this.status!==c.STATUS_EARLY_MEDIA&&this.status!==c.STATUS_ANSWERED||(this.status=c.STATUS_CANCELED,this.request.reply(487),this.canceled(i),this.rejected(i,e.C.causes.CANCELED),this.failed(i,e.C.causes.CANCELED),this.terminated(i,e.C.causes.CANCELED));break;case e.C.ACK:this.status===c.STATUS_WAITING_FOR_ACK&&(this.sessionDescriptionHandler.hasDescription(i.getHeader("Content-Type"))?(this.hasAnswer=!0,this.sessionDescriptionHandler.setDescription(i.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(s.bind(this),function(t){this.logger.warn(t),this.terminate({statusCode:"488",reasonPhrase:"Bad Media Description"}),this.failed(i,e.C.causes.BAD_MEDIA_DESCRIPTION),this.terminated(i,e.C.causes.BAD_MEDIA_DESCRIPTION)}.bind(this))):s.apply(this));break;case e.C.PRACK:this.status===c.STATUS_WAITING_FOR_PRACK||this.status===c.STATUS_ANSWERED_WAITING_FOR_PRACK?this.hasAnswer?(e.Timers.clearTimeout(this.timers.rel1xxTimer),e.Timers.clearTimeout(this.timers.prackTimer),i.reply(200),this.status===c.STATUS_ANSWERED_WAITING_FOR_PRACK&&(this.status=c.STATUS_EARLY_MEDIA,this.accept()),this.status=c.STATUS_EARLY_MEDIA):(this.sessionDescriptionHandler=this.setupSessionDescriptionHandler(),this.sessionDescriptionHandler.hasDescription(i.getHeader("Content-Type"))?(this.hasAnswer=!0,this.sessionDescriptionHandler.setDescription(i.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(function(){e.Timers.clearTimeout(this.timers.rel1xxTimer),e.Timers.clearTimeout(this.timers.prackTimer),i.reply(200),this.status===c.STATUS_ANSWERED_WAITING_FOR_PRACK&&(this.status=c.STATUS_EARLY_MEDIA,this.accept()),this.status=c.STATUS_EARLY_MEDIA}.bind(this),function(t){this.logger.warn(t),this.terminate({statusCode:"488",reasonPhrase:"Bad Media Description"}),this.failed(i,e.C.causes.BAD_MEDIA_DESCRIPTION),this.terminated(i,e.C.causes.BAD_MEDIA_DESCRIPTION)}.bind(this))):(this.terminate({statusCode:"488",reasonPhrase:"Bad Media Description"}),this.failed(i,e.C.causes.BAD_MEDIA_DESCRIPTION),this.terminated(i,e.C.causes.BAD_MEDIA_DESCRIPTION))):this.status===c.STATUS_EARLY_MEDIA&&i.reply(200);break;default:t.prototype.receiveRequest.apply(this,[i])}},setupSessionDescriptionHandler:function(){return this.sessionDescriptionHandler?this.sessionDescriptionHandler:this.sessionDescriptionHandlerFactory(this,this.ua.configuration.sessionDescriptionHandlerFactoryOptions)},onTransportError:function(){this.status!==c.STATUS_CONFIRMED&&this.status!==c.STATUS_TERMINATED&&this.failed(null,e.C.causes.CONNECTION_ERROR)},onRequestTimeout:function(){this.status===c.STATUS_CONFIRMED?this.terminated(null,e.C.causes.REQUEST_TIMEOUT):this.status!==c.STATUS_TERMINATED&&(this.failed(null,e.C.causes.REQUEST_TIMEOUT),this.terminated(null,e.C.causes.REQUEST_TIMEOUT))}},e.InviteServerContext=s,(r=function(t,i,s,r){s=s||{},this.passedOptions=s,s.params=Object.create(s.params||Object.prototype);var n=(s.extraHeaders||[]).slice(),o=t.configuration.sessionDescriptionHandlerFactory;if(this.sessionDescriptionHandlerFactoryOptions=t.configuration.sessionDescriptionHandlerFactoryOptions||{},this.sessionDescriptionHandlerOptions=s.sessionDescriptionHandlerOptions||{},this.modifiers=r,this.inviteWithoutSdp=s.inviteWithoutSdp||!1,this.anonymous=s.anonymous||!1,this.renderbody=s.renderbody||null,this.rendertype=s.rendertype||"text/plain",this.from_tag=e.Utils.newTag(),s.params.from_tag=this.from_tag,this.contact=t.contact.toString({anonymous:this.anonymous,outbound:this.anonymous?!t.contact.temp_gruu:!t.contact.pub_gruu}),this.anonymous&&(s.params.from_displayName="Anonymous",s.params.from_uri="sip:anonymous@anonymous.invalid",n.push("P-Preferred-Identity: "+t.configuration.uri.toString()),n.push("Privacy: id")),n.push("Contact: "+this.contact),n.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.inviteWithoutSdp&&this.renderbody&&(n.push("Content-Type: "+this.rendertype),n.push("Content-Disposition: render;handling=optional")),t.configuration.rel100===e.C.supported.REQUIRED&&n.push("Require: 100rel"),t.configuration.replaces===e.C.supported.REQUIRED&&n.push("Require: replaces"),s.extraHeaders=n,e.Utils.augment(this,e.ClientContext,[t,e.C.INVITE,i,s]),e.Utils.augment(this,e.Session,[o]),this.status!==c.STATUS_NULL)throw new e.Exceptions.InvalidStateError(this.status);this.isCanceled=!1,this.received_100=!1,this.method=e.C.INVITE,this.receiveNonInviteResponse=this.receiveResponse,this.receiveResponse=this.receiveInviteResponse,this.logger=t.getLogger("sip.inviteclientcontext"),t.applicants[this]=this,this.id=this.request.call_id+this.from_tag,this.onInfo=s.onInfo}).prototype={invite:function(){var t=this;return this.ua.sessions[this.id]=this,this.inviteWithoutSdp?(this.request.body=t.renderbody,this.status=c.STATUS_INVITE_SENT,this.send()):(this.sessionDescriptionHandler=this.sessionDescriptionHandlerFactory(this,this.sessionDescriptionHandlerFactoryOptions),this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions,this.modifiers).then(function(e){t.isCanceled||t.status===c.STATUS_TERMINATED||(t.hasOffer=!0,t.request.body=e,t.status=c.STATUS_INVITE_SENT,t.send())},function(){t.status!==c.STATUS_TERMINATED&&(t.failed(null,e.C.causes.WEBRTC_ERROR),t.terminated(null,e.C.causes.WEBRTC_ERROR))})),this},receiveInviteResponse:function(t){var i,s=this,r=t.call_id+t.from_tag+t.to_tag,n=[],o={};if(this.status!==c.STATUS_TERMINATED&&t.method===e.C.INVITE){if(this.dialog&&t.status_code>=200&&t.status_code<=299){if(r!==this.dialog.id.toString()){if(!this.createDialog(t,"UAC",!0))return;return this.emit("ack",t.transaction.sendACK({body:e.Utils.generateFakeSDP(t.body)})),this.earlyDialogs[r].sendRequest(this,e.C.BYE),void(this.status!==c.STATUS_CONFIRMED&&(this.failed(t,e.C.causes.WEBRTC_ERROR),this.terminated(t,e.C.causes.WEBRTC_ERROR)))}if(this.status===c.STATUS_CONFIRMED)return void this.emit("ack",t.transaction.sendACK());if(!this.hasAnswer)return}if(this.dialog&&t.status_code<200){if(-1!==this.dialog.pracked.indexOf(t.getHeader("rseq"))||this.dialog.pracked[this.dialog.pracked.length-1]>=t.getHeader("rseq")&&this.dialog.pracked.length>0)return;if(!this.earlyDialogs[r]&&!this.createDialog(t,"UAC",!0))return;if(-1!==this.earlyDialogs[r].pracked.indexOf(t.getHeader("rseq"))||this.earlyDialogs[r].pracked[this.earlyDialogs[r].pracked.length-1]>=t.getHeader("rseq")&&this.earlyDialogs[r].pracked.length>0)return;return n.push("RAck: "+t.getHeader("rseq")+" "+t.getHeader("cseq")),this.earlyDialogs[r].pracked.push(t.getHeader("rseq")),void this.earlyDialogs[r].sendRequest(this,e.C.PRACK,{extraHeaders:n,body:e.Utils.generateFakeSDP(t.body)})}if(this.isCanceled)t.status_code>=100&&t.status_code<200?(this.request.cancel(this.cancelReason,n),this.canceled(null)):t.status_code>=200&&t.status_code<299?(this.acceptAndTerminate(t),this.emit("bye",this.request)):t.status_code>=300&&(i=e.C.REASON_PHRASE[t.status_code]||e.C.causes.CANCELED,this.rejected(t,i),this.failed(t,i),this.terminated(t,i));else switch(!0){case/^100$/.test(t.status_code):this.received_100=!0,this.emit("progress",t);break;case/^1[0-9]{2}$/.test(t.status_code):if(!t.to_tag){this.logger.warn("1xx response received without to tag");break}if(t.hasHeader("contact")&&!this.createDialog(t,"UAC",!0))break;if(this.status=c.STATUS_1XX_RECEIVED,t.hasHeader("require")&&-1!==t.getHeader("require").indexOf("100rel")){if(this.dialog||!this.earlyDialogs[r])break;if(-1!==this.earlyDialogs[r].pracked.indexOf(t.getHeader("rseq"))||this.earlyDialogs[r].pracked[this.earlyDialogs[r].pracked.length-1]>=t.getHeader("rseq")&&this.earlyDialogs[r].pracked.length>0)return;if(this.sessionDescriptionHandler=this.sessionDescriptionHandlerFactory(this,this.sessionDescriptionHandlerFactoryOptions),this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type")))if(this.hasOffer){if(!this.createDialog(t,"UAC"))break;this.hasAnswer=!0,this.dialog.pracked.push(t.getHeader("rseq")),this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(function(){n.push("RAck: "+t.getHeader("rseq")+" "+t.getHeader("cseq")),s.sendRequest(e.C.PRACK,{extraHeaders:n,receiveResponse:function(){}}),s.status=c.STATUS_EARLY_MEDIA,s.emit("progress",t)},function(i){s.logger.warn(i),s.acceptAndTerminate(t,488,"Not Acceptable Here"),s.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION)})}else{var a=this.earlyDialogs[r],h=a.sessionDescriptionHandler=this.sessionDescriptionHandlerFactory(this,this.sessionDescriptionHandlerOptions);a.pracked.push(t.getHeader("rseq")),h.setDescription(t.body,s.sessionDescriptionHandlerOptions,s.modifers).then(h.getDescription.bind(h,s.sessionDescriptionHandlerOptions,s.modifiers)).then(function(i){n.push("RAck: "+t.getHeader("rseq")+" "+t.getHeader("cseq")),a.sendRequest(s,e.C.PRACK,{extraHeaders:n,body:i}),s.status=c.STATUS_EARLY_MEDIA,s.emit("progress",t)}).catch(function(i){if(i instanceof e.Exceptions.GetDescriptionError){if(a.pracked.push(t.getHeader("rseq")),s.status===c.STATUS_TERMINATED)return;s.failed(null,e.C.causes.WEBRTC_ERROR),s.terminated(null,e.C.causes.WEBRTC_ERROR)}else a.pracked.splice(a.pracked.indexOf(t.getHeader("rseq")),1),s.logger.warn("invalid description"),s.logger.warn(i)})}else n.push("RAck: "+t.getHeader("rseq")+" "+t.getHeader("cseq")),this.earlyDialogs[r].pracked.push(t.getHeader("rseq")),this.earlyDialogs[r].sendRequest(this,e.C.PRACK,{extraHeaders:n}),this.emit("progress",t)}else this.emit("progress",t);break;case/^2[0-9]{2}$/.test(t.status_code):if(this.request.cseq+" "+this.request.method!==t.getHeader("cseq"))break;if(this.status===c.STATUS_EARLY_MEDIA&&this.dialog){this.status=c.STATUS_CONFIRMED,o={},this.renderbody&&(n.push("Content-Type: "+this.rendertype),o.extraHeaders=n,o.body=this.renderbody),this.emit("ack",t.transaction.sendACK(o)),this.accepted(t);break}if(this.dialog)break;if(this.hasOffer)if(this.hasAnswer)this.renderbody&&(n.push("Content-Type: "+s.rendertype),o.extraHeaders=n,o.body=this.renderbody),this.emit("ack",t.transaction.sendACK(o));else{if(!this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type"))){this.acceptAndTerminate(t,400,"Missing session description"),this.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION);break}if(!this.createDialog(t,"UAC"))break;this.hasAnswer=!0,this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(function(){var e={};s.status=c.STATUS_CONFIRMED,s.renderbody&&(n.push("Content-Type: "+s.rendertype),e.extraHeaders=n,e.body=s.renderbody),s.emit("ack",t.transaction.sendACK(e)),s.accepted(t)},function(i){s.logger.warn(i),s.acceptAndTerminate(t,488,"Not Acceptable Here"),s.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION)})}else if(this.earlyDialogs[r]&&this.earlyDialogs[r].sessionDescriptionHandler){if(this.hasOffer=!0,this.hasAnswer=!0,this.sessionDescriptionHandler=this.earlyDialogs[r].sessionDescriptionHandler,!this.createDialog(t,"UAC"))break;this.status=c.STATUS_CONFIRMED,this.emit("ack",t.transaction.sendACK()),this.accepted(t)}else{if(this.sessionDescriptionHandler=this.sessionDescriptionHandlerFactory(this,this.sessionDescriptionHandlerFactoryOptions),!this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type"))){this.acceptAndTerminate(t,400,"Missing session description"),this.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION);break}if(!this.createDialog(t,"UAC"))break;this.hasOffer=!0,this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler,this.sessionDescriptionHandlerOptions,this.modifiers)).then(function(e){s.isCanceled||s.status===c.STATUS_TERMINATED||(s.status=c.STATUS_CONFIRMED,s.hasAnswer=!0,s.emit("ack",t.transaction.sendACK({body:e})),s.accepted(t))}).catch(function(i){i instanceof e.Exceptions.GetDescriptionError?s.logger.warn("there was a problem"):(s.logger.warn("invalid description"),s.logger.warn(i),s.acceptAndTerminate(t,488,"Invalid session description"),s.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION))})}break;default:i=e.Utils.sipErrorCause(t.status_code),this.rejected(t,i),this.failed(t,i),this.terminated(t,i)}}},cancel:function(t){if(t=t||{},t.extraHeaders=(t.extraHeaders||[]).slice(),this.status===c.STATUS_TERMINATED||this.status===c.STATUS_CONFIRMED)throw new e.Exceptions.InvalidStateError(this.status);this.logger.log("canceling RTCSession");var i=e.Utils.getCancelReason(t.status_code,t.reason_phrase);return this.status===c.STATUS_NULL||this.status===c.STATUS_INVITE_SENT&&!this.received_100?(this.isCanceled=!0,this.cancelReason=i):this.status!==c.STATUS_INVITE_SENT&&this.status!==c.STATUS_1XX_RECEIVED&&this.status!==c.STATUS_EARLY_MEDIA||this.request.cancel(i,t.extraHeaders),this.canceled()},terminate:function(e){return this.status===c.STATUS_TERMINATED?this:(this.status===c.STATUS_WAITING_FOR_ACK||this.status===c.STATUS_CONFIRMED?this.bye(e):this.cancel(e),this)},receiveRequest:function(i){return i.method,e.C.CANCEL,i.method===e.C.ACK&&this.status===c.STATUS_WAITING_FOR_ACK&&(e.Timers.clearTimeout(this.timers.ackTimer),e.Timers.clearTimeout(this.timers.invite2xxTimer),this.status=c.STATUS_CONFIRMED,this.accepted()),t.prototype.receiveRequest.apply(this,[i])},onTransportError:function(){this.status!==c.STATUS_CONFIRMED&&this.status!==c.STATUS_TERMINATED&&this.failed(null,e.C.causes.CONNECTION_ERROR)},onRequestTimeout:function(){this.status===c.STATUS_CONFIRMED?this.terminated(null,e.C.causes.REQUEST_TIMEOUT):this.status!==c.STATUS_TERMINATED&&(this.failed(null,e.C.causes.REQUEST_TIMEOUT),this.terminated(null,e.C.causes.REQUEST_TIMEOUT))}},e.InviteClientContext=r,(o=function(t,i,s,r){if(this.options=r||{},this.extraHeaders=(this.options.extraHeaders||[]).slice(),void 0===t||void 0===i||void 0===s)throw new TypeError("Not enough arguments");e.Utils.augment(this,e.ClientContext,[t,e.C.REFER,i.remoteIdentity.uri.toString(),r]),this.applicant=i;if(s instanceof e.InviteServerContext||s instanceof e.InviteClientContext)this.target='"'+s.remoteIdentity.friendlyName+'" <'+s.dialog.remote_target.toString()+"?Replaces="+s.dialog.id.call_id+"%3Bto-tag%3D"+s.dialog.id.remote_tag+"%3Bfrom-tag%3D"+s.dialog.id.local_tag+">";else{try{this.target=e.Grammar.parse(s,"Refer_To").uri||s}catch(e){this.logger.debug(".refer() cannot parse Refer_To from",s),this.logger.debug("...falling through to normalizeTarget()")}if(this.target=this.ua.normalizeTarget(this.target),!this.target)throw new TypeError("Invalid target: "+s)}this.ua&&this.extraHeaders.push("Referred-By: <"+this.ua.configuration.uri+">"),this.extraHeaders.push("Contact: "+i.contact),this.extraHeaders.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.extraHeaders.push("Refer-To: "+this.target)}).prototype={refer:function(t){t=t||{};var i=(this.extraHeaders||[]).slice();return t.extraHeaders&&i.concat(t.extraHeaders),this.applicant.sendRequest(e.C.REFER,{extraHeaders:this.extraHeaders,receiveResponse:function(e){/^1[0-9]{2}$/.test(e.status_code)?this.emit("referRequestProgress",this):/^2[0-9]{2}$/.test(e.status_code)?this.emit("referRequestAccepted",this):/^[4-6][0-9]{2}$/.test(e.status_code)&&this.emit("referRequestRejected",this),t.receiveResponse&&t.receiveResponse(e)}.bind(this)}),this},receiveNotify:function(t){if(t.hasHeader("Content-Type")&&-1!==t.getHeader("Content-Type").search(/^message\/sipfrag/)){var i=e.Grammar.parse(t.body,"sipfrag");if(-1===i)return void t.reply(489,"Bad Event");switch(!0){case/^1[0-9]{2}$/.test(i.status_code):this.emit("referProgress",this);break;case/^2[0-9]{2}$/.test(i.status_code):this.emit("referAccepted",this),!this.options.activeAfterTransfer&&this.applicant.terminate&&this.applicant.terminate();break;default:this.emit("referRejected",this)}return t.reply(200),void this.emit("notify",t)}t.reply(489,"Bad Event")}},e.ReferClientContext=o,(n=function(t,i){if(e.Utils.augment(this,e.ServerContext,[t,i]),this.ua=t,this.status=c.STATUS_INVITE_RECEIVED,this.from_tag=i.from_tag,this.id=i.call_id+this.from_tag,this.request=i,this.contact=this.ua.contact.toString(),this.logger=t.getLogger("sip.referservercontext",this.id),!this.request.hasHeader("refer-to"))return this.logger.warn("Invalid REFER packet. A refer-to header is required. Rejecting refer."),void this.reject();this.referTo=this.request.parseHeader("refer-to"),this.referredSession=this.ua.findSession(i),this.cseq=Math.floor(1e4*Math.random()),this.call_id=this.request.call_id,this.from_uri=this.request.to.uri,this.from_tag=this.request.to.parameters.tag,this.remote_target=this.request.headers.Contact[0].parsed.uri,this.to_uri=this.request.from.uri,this.to_tag=this.request.from_tag,this.route_set=this.request.getHeaders("record-route"),this.receiveNonInviteResponse=function(){},this.request.hasHeader("referred-by")&&(this.referredBy=this.request.getHeader("referred-by")),this.referTo.uri.hasHeader("replaces")&&(this.replaces=this.referTo.uri.getHeader("replaces")),this.status=c.STATUS_WAITING_FOR_ANSWER}).prototype={progress:function(){if(this.status!==c.STATUS_WAITING_FOR_ANSWER)throw new e.Exceptions.InvalidStateError(this.status);this.request.reply(100)},reject:function(t){if(this.status===c.STATUS_TERMINATED)throw new e.Exceptions.InvalidStateError(this.status);this.logger.log("Rejecting refer"),this.status=c.STATUS_TERMINATED,e.ServerContext.prototype.reject.call(this,t),this.emit("referRequestRejected",this)},accept:function(t,i){if(t=t||{},this.status!==c.STATUS_WAITING_FOR_ANSWER)throw new e.Exceptions.InvalidStateError(this.status);if(this.status=c.STATUS_ANSWERED,this.request.reply(202,"Accepted"),this.emit("referRequestAccepted",this),t.followRefer){this.logger.log("Accepted refer, attempting to automatically follow it");var s=this.referTo.uri;if(!s.scheme.match("^sips?$"))return this.logger.error("SIP.js can only automatically follow SIP refer target"),void this.reject();var r=t.inviteOptions||{},n=(r.extraHeaders||[]).slice();this.replaces&&n.push("Replaces: "+decodeURIComponent(this.replaces)),this.referredBy&&n.push("Referred-By: "+this.referredBy),r.extraHeaders=n,s.clearHeaders(),this.targetSession=this.ua.invite(s,r,i),this.emit("referInviteSent",this),this.targetSession.once("progress",function(){this.sendNotify("SIP/2.0 100 Trying"),this.emit("referProgress",this),this.referredSession&&this.referredSession.emit("referProgress",this)}.bind(this)),this.targetSession.once("accepted",function(){this.logger.log("Successfully followed the refer"),this.sendNotify("SIP/2.0 200 OK"),this.emit("referAccepted",this),this.referredSession&&this.referredSession.emit("referAccepted",this)}.bind(this));var o=function(e){if(this.status!==c.STATUS_TERMINATED){if(this.logger.log("Refer was not successful. Resuming session"),e&&429===e.status_code)return this.logger.log("Alerting referrer that identity is required."),void this.sendNotify("SIP/2.0 429 Provide Referrer Identity");this.sendNotify("SIP/2.0 603 Declined"),this.status=c.STATUS_TERMINATED,this.emit("referRejected",this),this.referredSession&&this.referredSession.emit("referRejected")}};this.targetSession.once("rejected",o.bind(this)),this.targetSession.once("failed",o.bind(this))}else this.logger.log("Accepted refer, but did not automatically follow it"),this.sendNotify("SIP/2.0 200 OK"),this.emit("referAccepted",this),this.referredSession&&this.referredSession.emit("referAccepted",this)},sendNotify:function(t){if(this.status!==c.STATUS_ANSWERED)throw new e.Exceptions.InvalidStateError(this.status);if(-1===e.Grammar.parse(t,"sipfrag"))throw new Error("sipfrag body is required to send notify for refer");var i=new e.OutgoingRequest(e.C.NOTIFY,this.remote_target,this.ua,{cseq:this.cseq+=1,call_id:this.call_id,from_uri:this.from_uri,from_tag:this.from_tag,to_uri:this.to_uri,to_tag:this.to_tag,route_set:this.route_set},["Event: refer","Subscription-State: terminated","Content-Type: message/sipfrag"],t);new e.RequestSender({request:i,onRequestTimeout:function(){},onTransportError:function(){},receiveResponse:function(){}},this.ua).send()}},e.ReferServerContext=n}},function(e,t,i){"use strict";e.exports=function(e){var t;return t=function(i,s,r){var n,o;if(void 0===s)throw new TypeError("Not enough arguments");if(this.logger=i.ua.getLogger("sip.invitecontext.dtmf",i.id),this.owner=i,this.direction=null,r=r||{},n=r.duration||null,o=r.interToneGap||null,"string"==typeof s)s=s.toUpperCase();else{if("number"!=typeof s)throw new TypeError("Invalid tone: "+s);s=s.toString()}if(!s.match(/^[0-9A-D#*]$/))throw new TypeError("Invalid tone: "+s);if(this.tone=s,n&&!e.Utils.isDecimal(n))throw new TypeError("Invalid tone duration: "+n);if(n?nt.C.MAX_DURATION?(this.logger.warn('"duration" value is greater than the maximum allowed, setting it to '+t.C.MAX_DURATION+" milliseconds"),n=t.C.MAX_DURATION):n=Math.abs(n):n=t.C.DEFAULT_DURATION,this.duration=n,o&&!e.Utils.isDecimal(o))throw new TypeError("Invalid interToneGap: "+o);o?o=300||"notify_wait"!==this.state&&-1!==this.errorCodes.indexOf(t.status_code)?this.failed(t,null):/^2[0-9]{2}$/.test(t.status_code)?(this.emit("accepted",t,s),(i=t.getHeader("Expires"))&&i<=this.requestedExpires?(this.expires=i,this.timers.sub_duration=e.Timers.setTimeout(this.refresh.bind(this),900*i)):i?(this.logger.warn("Expires header in a 200-class response to SUBSCRIBE with a higher value than the one in the request"),this.failed(t,e.C.INVALID_EXPIRES_HEADER)):(this.logger.warn("Expires header missing in a 200-class response to SUBSCRIBE"),this.failed(t,e.C.EXPIRES_HEADER_MISSING))):t.statusCode>300&&(this.emit("failed",t,s),this.emit("rejected",t,s))},unsubscribe:function(){var t=[];this.state="terminated",t.push("Event: "+this.event),t.push("Expires: 0"),t.push("Contact: "+this.contact),t.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.receiveResponse=function(){},this.dialog.sendRequest(this,this.method,{extraHeaders:t,body:this.body}),e.Timers.clearTimeout(this.timers.sub_duration),e.Timers.clearTimeout(this.timers.N),this.timers.N=e.Timers.setTimeout(this.timer_fire.bind(this),e.Timers.TIMER_N)},timer_fire:function(){"terminated"===this.state?(this.terminateDialog(),e.Timers.clearTimeout(this.timers.N),e.Timers.clearTimeout(this.timers.sub_duration),delete this.ua.subscriptions[this.id]):"notify_wait"===this.state||"pending"===this.state?this.close():this.refresh()},close:function(){"notify_wait"===this.state?(this.state="terminated",e.Timers.clearTimeout(this.timers.N),e.Timers.clearTimeout(this.timers.sub_duration),this.receiveResponse=function(){},delete this.ua.earlySubscriptions[this.request.call_id+this.request.from.parameters.tag+this.event]):"terminated"!==this.state&&this.unsubscribe()},createConfirmedDialog:function(t,i){var s;return this.terminateDialog(),s=new e.Dialog(this,t,i),s.invite_seqnum=this.request.cseq,s.local_seqnum=this.request.cseq,!s.error&&(this.dialog=s,!0)},terminateDialog:function(){this.dialog&&(delete this.ua.subscriptions[this.id],this.dialog.terminate(),delete this.dialog)},receiveRequest:function(t){function i(){s.expires&&(e.Timers.clearTimeout(r.timers.sub_duration),s.expires=Math.min(r.expires,Math.max(s.expires,0)),r.timers.sub_duration=e.Timers.setTimeout(r.refresh.bind(r),900*s.expires))}var s,r=this;if(this.matchEvent(t))if(this.dialog||this.createConfirmedDialog(t,"UAS")&&(this.id=this.dialog.id.toString(),delete this.ua.earlySubscriptions[this.request.call_id+this.request.from.parameters.tag+this.event],this.ua.subscriptions[this.id]=this),s=t.parseHeader("Subscription-State"),t.reply(200,e.C.REASON_200),e.Timers.clearTimeout(this.timers.N),this.emit("notify",{request:t}),"terminated"!==this.state)switch(s.state){case"active":this.state="active",i();break;case"pending":"notify_wait"===this.state&&i(),this.state="pending";break;case"terminated":if(e.Timers.clearTimeout(this.timers.sub_duration),s.reason)switch(this.logger.log("terminating subscription with reason "+s.reason),s.reason){case"deactivated":case"timeout":return void this.subscribe();case"probation":case"giveup":return void(s.params&&s.params["retry-after"]?this.timers.sub_duration=e.Timers.setTimeout(r.subscribe.bind(r),s.params["retry-after"]):this.subscribe())}this.close()}else"terminated"===s.state&&(this.terminateDialog(),e.Timers.clearTimeout(this.timers.N),e.Timers.clearTimeout(this.timers.sub_duration),delete this.ua.subscriptions[this.id]);else t.reply(489)},failed:function(e,t){return this.close(),this.emit("failed",e,t),this.emit("rejected",e,t),this},onDialogError:function(t){this.failed(t,e.C.causes.DIALOG_ERROR)},matchEvent:function(e){var t;return e.hasHeader("Event")?e.hasHeader("Subscription-State")?(t=e.parseHeader("event").event,this.event===t||(this.logger.warn("event match failed"),e.reply(481,"Event Match Failed"),!1)):(this.logger.warn("missing Subscription-State header"),!1):(this.logger.warn("missing Event header"),!1)}}}},function(e,t,i){"use strict";(function(t){var s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};e.exports=function(e,r){function n(t){if(t instanceof Function)return t.initialize||(t.initialize=function(){return e.Utils.Promise.resolve()}),t}var o,a={STATUS_INIT:0,STATUS_STARTING:1,STATUS_READY:2,STATUS_USER_CLOSED:3,STATUS_NOT_READY:4,CONFIGURATION_ERROR:1,NETWORK_ERROR:2,ALLOWED_METHODS:["ACK","CANCEL","INVITE","MESSAGE","BYE","OPTIONS","INFO","NOTIFY","REFER"],ACCEPTED_BODY_TYPES:["application/sdp","application/dtmf-relay"],MAX_FORWARDS:70,TAG_LENGTH:10};((o=function(t){function i(e){return s.emit.bind(s,e)}var s=this;a.ACCEPTED_BODY_TYPES=a.ACCEPTED_BODY_TYPES.toString(),this.log=new e.LoggerFactory,this.logger=this.getLogger("sip.ua"),this.cache={credentials:{}},this.configuration={},this.dialogs={},this.applicants={},this.data={},this.sessions={},this.subscriptions={},this.earlySubscriptions={},this.transport=null,this.contact=null,this.status=a.STATUS_INIT,this.error=null,this.transactions={nist:{},nict:{},ist:{},ict:{}},this.transportRecoverAttempts=0,this.transportRecoveryTimer=null,Object.defineProperties(this,{transactionsCount:{get:function(){var e,t=["nist","nict","ist","ict"],i=0;for(e in t)i+=Object.keys(this.transactions[t[e]]).length;return i}},nictTransactionsCount:{get:function(){return Object.keys(this.transactions.nict).length}},nistTransactionsCount:{get:function(){return Object.keys(this.transactions.nist).length}},ictTransactionsCount:{get:function(){return Object.keys(this.transactions.ict).length}},istTransactionsCount:{get:function(){return Object.keys(this.transactions.ist).length}}}),void 0===t?t={}:("string"==typeof t||t instanceof String)&&(t={uri:t}),t.log&&(t.log.hasOwnProperty("builtinEnabled")&&(this.log.builtinEnabled=t.log.builtinEnabled),t.log.hasOwnProperty("level")&&(this.log.level=t.log.level),t.log.hasOwnProperty("connector")&&(this.log.connector=t.log.connector));try{this.loadConfig(t)}catch(e){throw this.status=a.STATUS_NOT_READY,this.error=a.CONFIGURATION_ERROR,e}this.registerContext=new e.RegisterContext(this),this.registerContext.on("failed",i("registrationFailed")),this.registerContext.on("registered",i("registered")),this.registerContext.on("unregistered",i("unregistered")),this.configuration.autostart&&this.start()}).prototype=Object.create(e.EventEmitter.prototype)).register=function(e){return this.configuration.register=!0,this.registerContext.register(e),this},o.prototype.unregister=function(e){this.configuration.register=!1;var t=this.registerContext;return this.afterConnected(t.unregister.bind(t,e)),this},o.prototype.isRegistered=function(){return this.registerContext.registered},o.prototype.isConnected=function(){return!!this.transport&&this.transport.connected},o.prototype.afterConnected=function(e){this.isConnected()?e():this.once("connected",e)},o.prototype.waitForConnected=function(){return new e.Utils.Promise(function(e){this.afterConnected(e)}.bind(this))},o.prototype.invite=function(t,i,s){var r=new e.InviteClientContext(this,t,i,s);return this.waitForConnected().then(function(){r.invite(),this.emit("inviteSent",r)}.bind(this)),r},o.prototype.subscribe=function(t,i,s){var r=new e.Subscription(this,t,i,s);return this.afterConnected(r.subscribe.bind(r)),r},o.prototype.message=function(t,i,s){if(void 0===i)throw new TypeError("Not enough arguments");return(s=Object.create(s||Object.prototype)).contentType||(s.contentType="text/plain"),s.body=i,this.request(e.C.MESSAGE,t,s)},o.prototype.request=function(t,i,s){var r=new e.ClientContext(this,t,i,s);return this.afterConnected(r.send.bind(r)),r},o.prototype.stop=function(){function i(){0===c.nistTransactionsCount&&0===c.nictTransactionsCount&&(c.removeListener("transactionDestroyed",i),c.transport.disconnect())}var s,n,o,c=this;if(this.logger.log("user requested closure..."),this.status===a.STATUS_USER_CLOSED)return this.logger.warn("UA already closed"),this;e.Timers.clearTimeout(this.transportRecoveryTimer),this.logger.log("closing registerContext"),this.registerContext.close();for(s in this.sessions)this.logger.log("closing session "+s),this.sessions[s].terminate();for(n in this.subscriptions)this.logger.log("unsubscribing from subscription "+n),this.subscriptions[n].close();for(n in this.earlySubscriptions)this.logger.log("unsubscribing from early subscription "+n),this.earlySubscriptions[n].close();for(o in this.applicants)this.applicants[o].close();return this.status=a.STATUS_USER_CLOSED,0===this.nistTransactionsCount&&0===this.nictTransactionsCount?this.transport.disconnect():this.on("transactionDestroyed",i),"function"==typeof r.removeEventListener&&(t.chrome&&t.chrome.app&&t.chrome.app.runtime||r.removeEventListener("unload",this.environListener)),this},o.prototype.start=function(){var i;return this.logger.log("user requested startup..."),this.status===a.STATUS_INIT?(i=this.getNextWsServer(),this.status=a.STATUS_STARTING,new e.Transport(this,i)):this.status===a.STATUS_USER_CLOSED?(this.logger.log("resuming"),this.status=a.STATUS_READY,this.transport.connect()):this.status===a.STATUS_STARTING?this.logger.log("UA is in STARTING status, not opening new connection"):this.status===a.STATUS_READY?this.logger.log("UA is in READY status, not resuming"):this.logger.error("Connection is down. Auto-Recovery system is trying to connect"),this.configuration.autostop&&"function"==typeof r.addEventListener&&(t.chrome&&t.chrome.app&&t.chrome.app.runtime||(this.environListener=this.stop.bind(this),r.addEventListener("unload",this.environListener))),this},o.prototype.normalizeTarget=function(t){return e.Utils.normalizeTarget(t,this.configuration.hostportParams)},o.prototype.saveCredentials=function(e){return this.cache.credentials[e.realm]=this.cache.credentials[e.realm]||{},this.cache.credentials[e.realm][e.uri]=e,this},o.prototype.getCredentials=function(e){var t,i;return t=e.ruri.host,this.cache.credentials[t]&&this.cache.credentials[t][e.ruri]&&((i=this.cache.credentials[t][e.ruri]).method=e.method),i},o.prototype.getLogger=function(e,t){return this.log.getLogger(e,t)},o.prototype.onTransportClosed=function(t){var i,s,r,n=["nict","ict","nist","ist"];for(t.server.status=e.Transport.C.STATUS_DISCONNECTED,this.logger.log("connection state set to "+e.Transport.C.STATUS_DISCONNECTED),r=n.length,i=0;i0?(t.reply(200,null),this.emit("notify",{request:t})):t.reply(481,"Subscription does not exist");break;case e.C.REFER:if(this.logger.log("Received an out of dialog refer"),this.configuration.allowOutOfDialogRefers){this.logger.log("Allow out of dialog refers is enabled on the UA");var l=new e.ReferServerContext(this,t);this.listeners("outOfDialogReferRequested").length?this.emit("outOfDialogReferRequested",l):(this.logger.log("No outOfDialogReferRequest listeners, automatically accepting and following the out of dialog refer"),l.accept({followRefer:!0}));break}t.reply(405);break;default:t.reply(405)}}else t.reply_sl(416)},o.prototype.findSession=function(e){return this.sessions[e.call_id+e.from_tag]||this.sessions[e.call_id+e.to_tag]||null},o.prototype.findDialog=function(e){return this.dialogs[e.call_id+e.from_tag+e.to_tag]||this.dialogs[e.call_id+e.to_tag+e.from_tag]||null},o.prototype.findEarlySubscription=function(e){return this.earlySubscriptions[e.call_id+e.to_tag+e.getHeader("event")]||null},o.prototype.getNextWsServer=function(){var t,i,s,r=[];for(i=this.configuration.wsServers.length,t=0;tr[0].weight?r=[s]:s.weight===r[0].weight&&r.push(s));return t=Math.floor(Math.random()*r.length),r[t]},o.prototype.closeSessionsOnTransportError=function(){var e;for(e in this.sessions)this.sessions[e].onTransportError();this.registerContext.onTransportClosed()},o.prototype.recoverTransport=function(t){var i,s,r,n,o;for(n=(t=t||this).transportRecoverAttempts,s=t.configuration.wsServers.length,i=0;it.configuration.connectionRecoveryMaxInterval&&(this.logger.log("time for next connection attempt exceeds connectionRecoveryMaxInterval, resetting counter"),r=t.configuration.connectionRecoveryMinInterval,n=0),this.logger.log("next connection attempt in "+r+" seconds"),this.transportRecoveryTimer=e.Timers.setTimeout(function(){t.transportRecoverAttempts=n+1,new e.Transport(t,o)},1e3*r)},o.prototype.loadConfig=function(t){function s(e,i){var s=e.replace(/([a-z][A-Z])/g,function(e){return e[0]+"_"+e[1].toLowerCase()});if(e!==s){var r=t.hasOwnProperty(e);t.hasOwnProperty(s)&&(i.warn(s+" is deprecated, please use "+e),r&&i.warn(e+" overriding "+s)),t[e]=r?t[e]:t[s]}}var r,o,a,c,h,u={viaHost:e.Utils.createRandomToken(12)+".invalid",uri:new e.URI("sip","anonymous."+e.Utils.createRandomToken(6),"anonymous.invalid",null,null),wsServers:[{scheme:"WSS",sip_uri:"",status:0,weight:0,ws_uri:"wss://edge.sip.onsip.com"}],custom:{},displayName:"",password:null,registerExpires:600,register:!0,registrarServer:null,wsServerMaxReconnection:3,wsServerReconnectionTimeout:4,connectionRecoveryMinInterval:2,connectionRecoveryMaxInterval:30,keepAliveInterval:0,extraSupported:[],usePreloadedRoute:!1,userAgentString:e.C.USER_AGENT,noAnswerTimeout:60,traceSip:!1,hackViaTcp:!1,hackIpInContact:!1,hackWssInTransport:!1,hackAllowUnregisteredOptionTags:!1,sessionDescriptionHandlerFactoryOptions:{constraints:{},peerConnectionOptions:{}},contactName:e.Utils.createRandomToken(8),contactTransport:"ws",forceRport:!1,autostart:!0,autostop:!0,rel100:e.C.supported.UNSUPPORTED,replaces:e.C.supported.UNSUPPORTED,sessionDescriptionHandlerFactory:i(27)(e).defaultFactory,authenticationFactory:n(function(t){return new e.DigestAuthentication(t)}),allowLegacyNotifications:!1,allowOutOfDialogRefers:!1},l=this.getConfigurationCheck();for(r in l.mandatory){if(s(r,this.logger),!t.hasOwnProperty(r))throw new e.Exceptions.ConfigurationError(r);if(o=t[r],void 0===(a=l.mandatory[r](o)))throw new e.Exceptions.ConfigurationError(r,o);u[r]=a}for(r in l.optional)if(s(r,this.logger),t.hasOwnProperty(r)){if((o=t[r])instanceof Array&&0===o.length)continue;if(null===o||""===o||void 0===o)continue;if("number"==typeof o&&isNaN(o))continue;if(void 0===(a=l.optional[r](o)))throw new e.Exceptions.ConfigurationError(r,o);u[r]=a}if(u.connectionRecoveryMaxInterval"}};var d={};for(r in u)d[r]={value:u[r],writable:"register"===r||"custom"===r,configurable:!1};Object.defineProperties(this.configuration,d),this.logger.log("configuration parameters after validation:");for(r in u)switch(r){case"uri":case"registrarServer":case"sessionDescriptionHandlerFactory":this.logger.log("\xb7 "+r+": "+u[r]);break;case"password":this.logger.log("\xb7 "+r+": NOT SHOWN");break;default:this.logger.log("\xb7 "+r+": "+JSON.stringify(u[r]))}},o.prototype.getConfigurationCheck=function(){return{mandatory:{},optional:{uri:function(t){var i;return/^sip:/i.test(t)||(t=e.C.SIP+":"+t),(i=e.URI.parse(t))&&i.user?i:void 0},wsServers:function(t){var i,s,r;if("string"==typeof t)t=[{ws_uri:t}];else{if(!(t instanceof Array))return;for(s=t.length,i=0;i",t[i].weight||(t[i].weight=0),t[i].status=0,t[i].scheme=r.scheme.toUpperCase()}return t},authorizationUser:function(t){return-1===e.Grammar.parse('"'+t+'"',"quoted_string")?void 0:t},connectionRecoveryMaxInterval:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},connectionRecoveryMinInterval:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},displayName:function(t){return-1===e.Grammar.parse('"'+t+'"',"displayName")?void 0:t},hackViaTcp:function(e){if("boolean"==typeof e)return e},hackIpInContact:function(t){return"boolean"==typeof t?t:"string"==typeof t&&-1!==e.Grammar.parse(t,"host")?t:void 0},hackWssInTransport:function(e){if("boolean"==typeof e)return e},hackAllowUnregisteredOptionTags:function(e){if("boolean"==typeof e)return e},contactTransport:function(e){if("string"==typeof e)return e},forceRport:function(e){if("boolean"==typeof e)return e},instanceId:function(t){if("string"==typeof t)return/^uuid:/i.test(t)&&(t=t.substr(5)),-1===e.Grammar.parse(t,"uuid")?void 0:t},keepAliveInterval:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},extraSupported:function(e){var t,i;if(e instanceof Array){for(i=e.length,t=0;t0)return i},password:function(e){return String(e)},rel100:function(t){return t===e.C.supported.REQUIRED?e.C.supported.REQUIRED:t===e.C.supported.SUPPORTED?e.C.supported.SUPPORTED:e.C.supported.UNSUPPORTED},replaces:function(t){return t===e.C.supported.REQUIRED?e.C.supported.REQUIRED:t===e.C.supported.SUPPORTED?e.C.supported.SUPPORTED:e.C.supported.UNSUPPORTED},register:function(e){if("boolean"==typeof e)return e},registerExpires:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},registrarServer:function(t){var i;if("string"==typeof t)return/^sip:/i.test(t)||(t=e.C.SIP+":"+t),(i=e.URI.parse(t))?i.user?void 0:i:void 0},traceSip:function(e){if("boolean"==typeof e)return e},userAgentString:function(e){if("string"==typeof e)return e},usePreloadedRoute:function(e){if("boolean"==typeof e)return e},wsServerMaxReconnection:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},wsServerReconnectionTimeout:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},autostart:function(e){if("boolean"==typeof e)return e},autostop:function(e){if("boolean"==typeof e)return e},sessionDescriptionHandlerFactory:function(e){if(e instanceof Function)return e},sessionDescriptionHandlerFactoryOptions:function(e){if("object"===(void 0===e?"undefined":s(e)))return e},authenticationFactory:n,allowLegacyNotifications:function(e){if("boolean"==typeof e)return e},custom:function(e){if("object"===(void 0===e?"undefined":s(e)))return e},contactName:function(e){if("string"==typeof e)return e}}}},o.C=a,e.UA=o}}).call(t,i(0))},function(e,t,i){"use strict";(function(t){e.exports=function(e){var i=function(e,i){this.options=i||{},this.logger=e.ua.getLogger("sip.invitecontext.sessionDescriptionHandler",e.id),this.session=e,this.CONTENT_TYPE="application/sdp",this.modifiers=this.options.modifiers||[],Array.isArray(this.modifiers)||(this.modifiers=[this.modifiers]);var s=t.window||t;this.WebRTC={MediaStream:s.MediaStream,getUserMedia:s.navigator.mediaDevices.getUserMedia.bind(s.navigator.mediaDevices),RTCPeerConnection:s.RTCPeerConnection,RTCSessionDescription:s.RTCSessionDescription},this.iceGatheringDeferred=null,this.iceGatheringTimeout=!1,this.iceGatheringTimer=null,this.initPeerConnection(this.options.peerConnectionOptions),this.constraints=this.checkAndDefaultConstraints(this.options.constraints),this.session.emit("SessionDescriptionHandler-created",this)};return i.defaultFactory=function(e,t){return new i(e,t)},i.prototype=Object.create(e.SessionDescriptionHandler.prototype,{close:{writable:!0,value:function(){this.logger.log("closing PeerConnection"),this.peerConnection&&"closed"!==this.peerConnection.signalingState&&(this.peerConnection.getSenders?this.peerConnection.getSenders().forEach(function(e){e.track&&e.track.stop()}):(this.logger.warn("Using getLocalStreams which is deprecated"),this.peerConnection.getLocalStreams().forEach(function(e){e.getTracks().forEach(function(e){e.stop()})})),this.peerConnection.getReceivers?this.peerConnection.getReceivers().forEach(function(e){e.track&&e.track.stop()}):(this.logger.warn("Using getRemoteStreams which is deprecated"),this.peerConnection.getRemoteStreams().forEach(function(e){e.getTracks().forEach(function(e){e.stop()})})),this.resetIceGatheringComplete(),this.peerConnection.close())}},getDescription:{writable:!0,value:function(t,i){var s=this,r=!0;if(this.session.disableRenegotiation)return this.logger.warn('The flag "disableRenegotiation" is set to true for this session description handler. We will not try to renegotiate.'),e.Utils.Promise.reject(new e.Exceptions.RenegotiationError("disableRenegotiation flag set to true for this session description handler"));(t=t||{}).peerConnectionOptions&&this.initPeerConnection(t.peerConnectionOptions);var n=Object.assign({},this.constraints,t.constraints);return n=this.checkAndDefaultConstraints(n),JSON.stringify(n)!==JSON.stringify(this.constraints)?this.constraints=n:r=!1,i=i||[],Array.isArray(i)||(i=[i]),i=i.concat(this.modifiers),!r&&this.peerConnection.localDescription&&this.peerConnection.localDescription.sdp&&""!==this.peerConnection.localDescription.sdp?this.createOfferOrAnswer(t.RTCOfferOptions,i).then(function(e){return{body:e,contentType:s.CONTENT_TYPE}}):(s.logger.log("acquiring local media"),this.acquire(s.constraints).then(function(e){return s.logger.log("acquired local media streams"),e},function(e){throw s.logger.error("unable to acquire streams"),s.logger.error(e),e}).then(function(t){try{(t=[].concat(t)).forEach(function(e){s.peerConnection.addTrack?e.getTracks().forEach(function(t){s.peerConnection.addTrack(t,e)}):s.peerConnection.addStream(e)},this)}catch(t){return s.logger.error("error adding stream"),s.logger.error(t),e.Utils.Promise.reject(t)}return e.Utils.Promise.resolve()}).then(function(){return s.createOfferOrAnswer(t.RTCOfferOptions,i)}).then(function(e){return{body:e,contentType:s.CONTENT_TYPE}}).catch(function(e){throw this.session.disableRenegotiation=!0,e}))}},hasDescription:{writable:!0,value:function(e){return e===this.CONTENT_TYPE}},holdModifier:{writable:!0,value:function(t){return/a=(sendrecv|sendonly|recvonly|inactive)/.test(t.sdp)?(t.sdp=t.sdp.replace(/a=sendrecv\r\n/g,"a=sendonly\r\n"),t.sdp=t.sdp.replace(/a=recvonly\r\n/g,"a=inactive\r\n")):t.sdp=t.sdp.replace(/(m=[^\r]*\r\n)/g,"$1a=sendonly\r\n"),e.Utils.Promise.resolve(t)}},setDescription:{writable:!0,value:function(t,i,s){var r=this,n="undefined"!=typeof InstallTrigger;if(!this.session.disableRenegotiation&&n&&this.peerConnection&&this.isVideoHold(t)&&(this.session.disableRenegotiation=!0),this.session.disableRenegotiation)return this.logger.warn('The flag "disableRenegotiation" is set to true for this session description handler. We will not try to renegotiate.'),e.Utils.Promise.reject(new e.Exceptions.RenegotiationError("disableRenegotiation flag set to true for this session description handler"));(i=i||{}).peerConnectionOptions&&this.initPeerConnection(i.peerConnectionOptions),this.constraints=Object.assign({},this.constraints,i.constraints),this.constraints=this.checkAndDefaultConstraints(this.constraints),s=s||[],Array.isArray(s)||(s=[s]),s=s.concat(this.modifiers);var o={type:this.hasOffer("local")?"answer":"offer",sdp:t};return e.Utils.reducePromises(s,o).catch(function(e){throw r.logger.error("The modifiers did not resolve successfully"),r.logger.error(e),e}).then(function(e){return r.emit("setDescription",e),r.peerConnection.setRemoteDescription(new r.WebRTC.RTCSessionDescription(e))}).catch(function(e){throw r.session.disableRenegotiation=!0,r.logger.error(e),r.emit("peerConnection-setRemoteDescriptionFailed",e),e}).then(function(){r.peerConnection.getReceivers?r.emit("setRemoteDescription",r.peerConnection.getReceivers()):r.emit("setRemoteDescription",r.peerConnection.getRemoteStreams()),r.emit("confirmed",r)})}},createOfferOrAnswer:{writable:!0,value:function(t,i){var s,r=this,n=this.peerConnection;return t=t||{},s=r.hasOffer("remote")?"createAnswer":"createOffer",n[s](t).catch(function(e){throw r.emit("peerConnection-"+s+"Failed",e),e}).then(function(t){return e.Utils.reducePromises(i,t)}).then(function(e){return r.logger.log(e),n.setLocalDescription(e)}).catch(function(e){throw r.emit("peerConnection-SetLocalDescriptionFailed",e),e}).then(function(){return r.waitForIceGatheringComplete()}).then(function(){var t=r.peerConnection.localDescription;return e.Utils.reducePromises(i,t)}).then(function(e){return r.emit("getDescription",e),e.sdp}).catch(function(t){throw r.logger.error(t),new e.Exceptions.GetDescriptionError(t)})}},addDefaultIceCheckingTimeout:{writable:!0,value:function(e){return void 0===e.iceCheckingTimeout&&(e.iceCheckingTimeout=5e3),e}},addDefaultIceServers:{writable:!0,value:function(e){return e.iceServers||(e.iceServers=[{urls:"stun:stun.l.google.com:19302"}]),e}},checkAndDefaultConstraints:{writable:!0,value:function(e){var t={audio:!0,video:!0};return e=e||t,0===Object.keys(e).length&&e.constructor===Object?t:e}},initPeerConnection:{writable:!0,value:function(t){var i=this;t=t||{},(t=this.addDefaultIceCheckingTimeout(t)).rtcConfiguration=t.rtcConfiguration||{},t.rtcConfiguration=this.addDefaultIceServers(t.rtcConfiguration),this.logger.log("initPeerConnection"),this.peerConnection&&(this.logger.log("Already have a peer connection for this session. Tearing down."),this.resetIceGatheringComplete(),this.peerConnection.close()),this.peerConnection=new this.WebRTC.RTCPeerConnection(t.rtcConfiguration),this.logger.log("New peer connection created"),this.session.emit("peerConnection-created",this.peerConnection),this.peerConnection.ontrack=function(e){i.logger.log("track added"),i.emit("addTrack",e)},this.peerConnection.onaddstream=function(e){i.logger.warn("Using deprecated stream API"),i.logger.log("stream added"),i.emit("addStream",e)},this.peerConnection.onremovestream=function(e){i.logger.log("stream removed: "+e.stream.id)},this.peerConnection.onicecandidate=function(e){i.emit("iceCandidate",e),e.candidate&&i.logger.log("ICE candidate received: "+(null===e.candidate.candidate?null:e.candidate.candidate.trim()))},this.peerConnection.onicegatheringstatechange=function(){switch(i.logger.log("RTCIceGatheringState changed: "+this.iceGatheringState),this.iceGatheringState){case"gathering":i.emit("iceGathering",this),!i.iceGatheringTimer&&t.iceCheckingTimeout&&(i.iceGatheringTimeout=!1,i.iceGatheringTimer=e.Timers.setTimeout(function(){i.logger.log("RTCIceChecking Timeout Triggered after "+t.iceCheckingTimeout+" milliseconds"),i.iceGatheringTimeout=!0,i.triggerIceGatheringComplete()},t.iceCheckingTimeout));break;case"complete":i.triggerIceGatheringComplete()}},this.peerConnection.oniceconnectionstatechange=function(){var e;switch(this.iceConnectionState){case"new":e="iceConnection";break;case"checking":e="iceConnectionChecking";break;case"connected":e="iceConnectionConnected";break;case"completed":e="iceConnectionCompleted";break;case"failed":e="iceConnectionFailed";break;case"disconnected":e="iceConnectionDisconnected";break;case"closed":e="iceConnectionClosed";break;default:return void i.logger.warn("Unknown iceConnection state:",this.iceConnectionState)}i.emit(e,this)}}},acquire:{writable:!0,value:function(t){return t=this.checkAndDefaultConstraints(t),new e.Utils.Promise(function(e,i){this.emit("userMediaRequest",t);var s=function(e,t){var i=Array.prototype.slice.call(arguments,2),s=[e].concat(i);return this.emit.apply(this,s),t.apply(null,i)}.bind(this);t.audio||t.video?this.WebRTC.getUserMedia(t).then(s.bind(this,"userMedia",function(t){e(t)}),s.bind(this,"userMediaFailed",function(e){throw i(e),e})):e([])}.bind(this))}},isVideoHold:{writable:!0,value:function(e){return-1!==e.search(/^(m=video.*?)[\s\S]*^(a=sendonly?)/gm)}},hasOffer:{writable:!0,value:function(e){var t="have-"+e+"-offer";return this.peerConnection.signalingState===t}},isIceGatheringComplete:{writable:!0,value:function(){return"complete"===this.peerConnection.iceGatheringState||this.iceGatheringTimeout}},resetIceGatheringComplete:{writable:!0,value:function(){this.iceGatheringTimeout=!1,this.iceGatheringTimer&&(e.Timers.clearTimeout(this.iceGatheringTimer),this.iceGatheringTimer=null),this.iceGatheringDeferred&&(this.iceGatheringDeferred.reject(),this.iceGatheringDeferred=null)}},triggerIceGatheringComplete:{writable:!0,value:function(){this.isIceGatheringComplete()&&(this.emit("iceGatheringComplete",this),this.iceGatheringTimer&&(e.Timers.clearTimeout(this.iceGatheringTimer),this.iceGatheringTimer=null),this.iceGatheringDeferred&&(this.iceGatheringDeferred.resolve(),this.iceGatheringDeferred=null))}},waitForIceGatheringComplete:{writable:!0,value:function(){return this.isIceGatheringComplete()?e.Utils.Promise.resolve():(this.isIceGatheringDeferred||(this.iceGatheringDeferred=e.Utils.defer()),this.iceGatheringDeferred.promise)}}}),i}}).call(t,i(0))},function(e,t,i){"use strict";e.exports=function(e){function t(t,i,s){for(var r,n=e.Utils.buildStatusLine(t),o=i.getHeaders("via"),a=o.length,c=0;c1)return t.getLogger("sip.sanitycheck").warn("More than one Via header field present in the response. Dropping the response"),!1}),r.push(function(e,t){var i=t.configuration.viaHost;if(e.via.host!==i||void 0!==e.via.port)return t.getLogger("sip.sanitycheck").warn("Via sent-by in the response does not match UA Via host value. Dropping the response"),!1}),r.push(function(t,i){if(e.Utils.str_utf8_length(t.body)-1)this.qop="auth";else{if(!(i.qop.indexOf("auth-int")>-1))return this.logger.warn('challenge without Digest qop different than "auth" or "auth-int", authentication aborted'),!1;this.qop="auth-int"}else this.qop=null;return this.method=t.method,this.uri=t.ruri,this.cnonce=e.createRandomToken(12),this.nc+=1,this.updateNcHex(),4294967296===this.nc&&(this.nc=1,this.ncHex="00000001"),this.calculateResponse(),!0},t.prototype.calculateResponse=function(){var t,i;t=e.calculateMD5(this.username+":"+this.realm+":"+this.password),"auth"===this.qop?(i=e.calculateMD5(this.method+":"+this.uri),this.response=e.calculateMD5(t+":"+this.nonce+":"+this.ncHex+":"+this.cnonce+":auth:"+i)):"auth-int"===this.qop?(i=e.calculateMD5(this.method+":"+this.uri+":"+e.calculateMD5(this.body?this.body:"")),this.response=e.calculateMD5(t+":"+this.nonce+":"+this.ncHex+":"+this.cnonce+":auth-int:"+i)):null===this.qop&&(i=e.calculateMD5(this.method+":"+this.uri),this.response=e.calculateMD5(t+":"+this.nonce+":"+i))},t.prototype.toString=function(){var e=[];if(!this.response)throw new Error("response field does not exist, cannot generate Authorization header");return e.push("algorithm="+this.algorithm),e.push('username="'+this.username+'"'),e.push('realm="'+this.realm+'"'),e.push('nonce="'+this.nonce+'"'),e.push('uri="'+this.uri+'"'),e.push('response="'+this.response+'"'),this.opaque&&e.push('opaque="'+this.opaque+'"'),this.qop&&(e.push("qop="+this.qop),e.push('cnonce="'+this.cnonce+'"'),e.push("nc="+this.ncHex)),"Digest "+e.join(", ")},t.prototype.updateNcHex=function(){var e=Number(this.nc).toString(16);this.ncHex="00000000".substr(0,8-e.length)+e},t}},function(e,t,i){"use strict";var s=i(31);e.exports=function(e){return{parse:function(t,i){var r={startRule:i,SIP:e};try{s.parse(t,r)}catch(e){r.data=-1}return r.data}}}},function(e,t,i){"use strict";function s(e,t,i,r){this.message=e,this.expected=t,this.found=i,this.location=r,this.name="SyntaxError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,s)}!function(e,t){function i(){this.constructor=e}i.prototype=t.prototype,e.prototype=new i}(s,Error),s.buildMessage=function(e,t){function i(e){return e.charCodeAt(0).toString(16).toUpperCase()}function s(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(e){return"\\x0"+i(e)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(e){return"\\x"+i(e)})}function r(e){return e.replace(/\\/g,"\\\\").replace(/\]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(e){return"\\x0"+i(e)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(e){return"\\x"+i(e)})}function n(e){return o[e.type](e)}var o={literal:function(e){return'"'+s(e.text)+'"'},class:function(e){var t,i="";for(t=0;t0){for(t=1,i=1;tR&&(R=E,v=[]),v.push(e))}function u(e,t,i){return new s(s.buildMessage(e,t),e,t,i)}function l(e){var t,i=new Array(e.length);for(t=0;tE?(a=n+3+r[n+1],n+=3):(a=n+3+r[n+1]+r[n+2],n+=3+r[n+1]);break;case 18:c.push(a),o.push(n+4+r[n+2]+r[n+3]),e.substr(E,m[r[n+1]].length)===m[r[n+1]]?(a=n+4+r[n+2],n+=4):(a=n+4+r[n+2]+r[n+3],n+=4+r[n+2]);break;case 19:c.push(a),o.push(n+4+r[n+2]+r[n+3]),e.substr(E,m[r[n+1]].length).toLowerCase()===m[r[n+1]]?(a=n+4+r[n+2],n+=4):(a=n+4+r[n+2]+r[n+3],n+=4+r[n+2]);break;case 20:c.push(a),o.push(n+4+r[n+2]+r[n+3]),m[r[n+1]].test(e.charAt(E))?(a=n+4+r[n+2],n+=4):(a=n+4+r[n+2]+r[n+3],n+=4+r[n+2]);break;case 21:u.push(e.substr(E,r[n+1])),E+=r[n+1],n+=2;break;case 22:u.push(m[r[n+1]]),E+=m[r[n+1]].length,n+=2;break;case 23:u.push(g),0===A&&h(m[r[n+1]]),n+=2;break;case 24:S=u[u.length-1-r[n+1]],n+=2;break;case 25:S=E,n++;break;case 26:for(i=r.slice(n+4,n+4+r[n+3]),s=0;s0))break;a=c.pop(),n=o.pop()}return u[0]}t=void 0!==t?t:{};var p,g={},f={Contact:118,Name_Addr_Header:155,Record_Route:175,Request_Response:81,SIP_URI:45,Subscription_State:185,Supported:190,Require:181,Via:193,absoluteURI:84,Call_ID:117,Content_Disposition:129,Content_Length:134,Content_Type:135,CSeq:145,displayName:121,Event:148,From:150,host:52,Max_Forwards:153,Min_SE:212,Proxy_Authenticate:156,quoted_string:40,Refer_To:177,Replaces:178,Session_Expires:209,stun_URI:216,To:191,turn_URI:222,uuid:225,WWW_Authenticate:208,challenge:157,sipfrag:229,Referred_By:230},T=118,m=["\r\n",n("\r\n",!1),/^[0-9]/,o([["0","9"]],!1,!1),/^[a-zA-Z]/,o([["a","z"],["A","Z"]],!1,!1),/^[0-9a-fA-F]/,o([["0","9"],["a","f"],["A","F"]],!1,!1),/^[\0-\xFF]/,o([["\0","\xff"]],!1,!1),/^["]/,o(['"'],!1,!1)," ",n(" ",!1),"\t",n("\t",!1),/^[a-zA-Z0-9]/,o([["a","z"],["A","Z"],["0","9"]],!1,!1),";",n(";",!1),"/",n("/",!1),"?",n("?",!1),":",n(":",!1),"@",n("@",!1),"&",n("&",!1),"=",n("=",!1),"+",n("+",!1),"$",n("$",!1),",",n(",",!1),"-",n("-",!1),"_",n("_",!1),".",n(".",!1),"!",n("!",!1),"~",n("~",!1),"*",n("*",!1),"'",n("'",!1),"(",n("(",!1),")",n(")",!1),"%",n("%",!1),function(){return" "},function(){return":"},/^[!-~]/,o([["!","~"]],!1,!1),/^[\x80-\uFFFF]/,o([["\x80","\uffff"]],!1,!1),/^[\x80-\xBF]/,o([["\x80","\xbf"]],!1,!1),/^[a-f]/,o([["a","f"]],!1,!1),"`",n("`",!1),"<",n("<",!1),">",n(">",!1),"\\",n("\\",!1),"[",n("[",!1),"]",n("]",!1),"{",n("{",!1),"}",n("}",!1),function(){return"*"},function(){return"/"},function(){return"="},function(){return"("},function(){return")"},function(){return">"},function(){return"<"},function(){return","},function(){return";"},function(){return":"},function(){return'"'},/^[!-']/,o([["!","'"]],!1,!1),/^[*-[]/,o([["*","["]],!1,!1),/^[\]-~]/,o([["]","~"]],!1,!1),function(e){return e},/^[#-[]/,o([["#","["]],!1,!1),/^[\0-\t]/,o([["\0","\t"]],!1,!1),/^[\x0B-\f]/,o([["\v","\f"]],!1,!1),/^[\x0E-\x7F]/,o([["\x0e","\x7f"]],!1,!1),function(){t.data.uri=new t.SIP.URI(t.data.scheme,t.data.user,t.data.host,t.data.port),delete t.data.scheme,delete t.data.user,delete t.data.host,delete t.data.host_type,delete t.data.port},function(){t.data.uri=new t.SIP.URI(t.data.scheme,t.data.user,t.data.host,t.data.port,t.data.uri_params,t.data.uri_headers),delete t.data.scheme,delete t.data.user,delete t.data.host,delete t.data.host_type,delete t.data.port,delete t.data.uri_params,"SIP_URI"===t.startRule&&(t.data=t.data.uri)},"sips",n("sips",!0),"sip",n("sip",!0),function(e){t.data.scheme=e},function(){t.data.user=decodeURIComponent(i().slice(0,-1))},function(){t.data.password=i()},function(){return t.data.host=i(),t.data.host},function(){return t.data.host_type="domain",i()},/^[a-zA-Z0-9_\-]/,o([["a","z"],["A","Z"],["0","9"],"_","-"],!1,!1),/^[a-zA-Z0-9\-]/,o([["a","z"],["A","Z"],["0","9"],"-"],!1,!1),function(){return t.data.host_type="IPv6",i()},"::",n("::",!1),function(){return t.data.host_type="IPv6",i()},function(){return t.data.host_type="IPv4",i()},"25",n("25",!1),/^[0-5]/,o([["0","5"]],!1,!1),"2",n("2",!1),/^[0-4]/,o([["0","4"]],!1,!1),"1",n("1",!1),/^[1-9]/,o([["1","9"]],!1,!1),function(e){return e=parseInt(e.join("")),t.data.port=e,e},"transport=",n("transport=",!0),"udp",n("udp",!0),"tcp",n("tcp",!0),"sctp",n("sctp",!0),"tls",n("tls",!0),function(e){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.transport=e.toLowerCase()},"user=",n("user=",!0),"phone",n("phone",!0),"ip",n("ip",!0),function(e){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.user=e.toLowerCase()},"method=",n("method=",!0),function(e){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.method=e},"ttl=",n("ttl=",!0),function(e){t.data.params||(t.data.params={}),t.data.params.ttl=e},"maddr=",n("maddr=",!0),function(e){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.maddr=e},"lr",n("lr",!0),function(){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.lr=void 0},function(e,i){t.data.uri_params||(t.data.uri_params={}),i=null===i?void 0:i[1],t.data.uri_params[e.toLowerCase()]=i&&i.toLowerCase()},function(e,i){e=e.join("").toLowerCase(),i=i.join(""),t.data.uri_headers||(t.data.uri_headers={}),t.data.uri_headers[e]?t.data.uri_headers[e].push(i):t.data.uri_headers[e]=[i]},function(){"Refer_To"===t.startRule&&(t.data.uri=new t.SIP.URI(t.data.scheme,t.data.user,t.data.host,t.data.port,t.data.uri_params,t.data.uri_headers),delete t.data.scheme,delete t.data.user,delete t.data.host,delete t.data.host_type,delete t.data.port,delete t.data.uri_params)},"//",n("//",!1),function(){t.data.scheme=i()},n("SIP",!0),function(){t.data.sip_version=i()},"INVITE",n("INVITE",!1),"ACK",n("ACK",!1),"VXACH",n("VXACH",!1),"OPTIONS",n("OPTIONS",!1),"BYE",n("BYE",!1),"CANCEL",n("CANCEL",!1),"REGISTER",n("REGISTER",!1),"SUBSCRIBE",n("SUBSCRIBE",!1),"NOTIFY",n("NOTIFY",!1),"REFER",n("REFER",!1),function(){return t.data.method=i(),t.data.method},function(e){t.data.status_code=parseInt(e.join(""))},function(){t.data.reason_phrase=i()},function(){t.data=i()},function(){var e,i;for(i=t.data.multi_header.length,e=0;e""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E'),l(";).# &;,"),l('2F""6F7G.} &2H""6H7I.q &2J""6J7K.e &2L""6L7M.Y &2N""6N7O.M &2P""6P7Q.A &2R""6R7S.5 &2T""6T7U.) &2V""6V7W'),l('%%2X""6X7Y/5#;#/,$;#/#$+#)(#\'#("\'#&\'#/"!&,)'),l('%%$;$0#*;$&/,#; /#$+")("\'#&\'#." &"/=#$;$/�#*;$&&&#/\'$8":Z" )("\'#&\'#'),l(';.." &"'),l("%$;'.# &;(0)*;'.# &;(&/?#28\"\"6879/0$;//'$8#:[# )(#'#(\"'#&'#"),l('%%$;2/�#*;2&&&#/g#$%$;.0#*;.&/,#;2/#$+")("\'#&\'#0=*%$;.0#*;.&/,#;2/#$+")("\'#&\'#&/#$+")("\'#&\'#/"!&,)'),l('4\\""5!7].# &;3'),l('4^""5!7_'),l('4`""5!7a'),l(';!.) &4b""5!7c'),l('%$;).\x95 &2F""6F7G.\x89 &2J""6J7K.} &2L""6L7M.q &2X""6X7Y.e &2P""6P7Q.Y &2H""6H7I.M &2@""6@7A.A &2d""6d7e.5 &2R""6R7S.) &2N""6N7O/\x9e#0\x9b*;).\x95 &2F""6F7G.\x89 &2J""6J7K.} &2L""6L7M.q &2X""6X7Y.e &2P""6P7Q.Y &2H""6H7I.M &2@""6@7A.A &2d""6d7e.5 &2R""6R7S.) &2N""6N7O&&&#/"!&,)'),l('%$;).\x89 &2F""6F7G.} &2L""6L7M.q &2X""6X7Y.e &2P""6P7Q.Y &2H""6H7I.M &2@""6@7A.A &2d""6d7e.5 &2R""6R7S.) &2N""6N7O/\x92#0\x8f*;).\x89 &2F""6F7G.} &2L""6L7M.q &2X""6X7Y.e &2P""6P7Q.Y &2H""6H7I.M &2@""6@7A.A &2d""6d7e.5 &2R""6R7S.) &2N""6N7O&&&#/"!&,)'),l('2T""6T7U.\xe3 &2V""6V7W.\xd7 &2f""6f7g.\xcb &2h""6h7i.\xbf &2:""6:7;.\xb3 &2D""6D7E.\xa7 &22""6273.\x9b &28""6879.\x8f &2j""6j7k.\x83 &;&.} &24""6475.q &2l""6l7m.e &2n""6n7o.Y &26""6677.M &2>""6>7?.A &2p""6p7q.5 &2r""6r7s.) &;\'.# &;('),l('%$;).\u012b &2F""6F7G.\u011f &2J""6J7K.\u0113 &2L""6L7M.\u0107 &2X""6X7Y.\xfb &2P""6P7Q.\xef &2H""6H7I.\xe3 &2@""6@7A.\xd7 &2d""6d7e.\xcb &2R""6R7S.\xbf &2N""6N7O.\xb3 &2T""6T7U.\xa7 &2V""6V7W.\x9b &2f""6f7g.\x8f &2h""6h7i.\x83 &28""6879.w &2j""6j7k.k &;&.e &24""6475.Y &2l""6l7m.M &2n""6n7o.A &26""6677.5 &2p""6p7q.) &2r""6r7s/\u0134#0\u0131*;).\u012b &2F""6F7G.\u011f &2J""6J7K.\u0113 &2L""6L7M.\u0107 &2X""6X7Y.\xfb &2P""6P7Q.\xef &2H""6H7I.\xe3 &2@""6@7A.\xd7 &2d""6d7e.\xcb &2R""6R7S.\xbf &2N""6N7O.\xb3 &2T""6T7U.\xa7 &2V""6V7W.\x9b &2f""6f7g.\x8f &2h""6h7i.\x83 &28""6879.w &2j""6j7k.k &;&.e &24""6475.Y &2l""6l7m.M &2n""6n7o.A &26""6677.5 &2p""6p7q.) &2r""6r7s&&&#/"!&,)'),l("%;//?#2P\"\"6P7Q/0$;//'$8#:t# )(#'#(\"'#&'#"),l("%;//?#24\"\"6475/0$;//'$8#:u# )(#'#(\"'#&'#"),l("%;//?#2>\"\"6>7?/0$;//'$8#:v# )(#'#(\"'#&'#"),l("%;//?#2T\"\"6T7U/0$;//'$8#:w# )(#'#(\"'#&'#"),l("%;//?#2V\"\"6V7W/0$;//'$8#:x# )(#'#(\"'#&'#"),l('%2h""6h7i/0#;//\'$8":y" )("\'#&\'#'),l('%;//6#2f""6f7g/\'$8":z" )("\'#&\'#'),l("%;//?#2D\"\"6D7E/0$;//'$8#:{# )(#'#(\"'#&'#"),l("%;//?#22\"\"6273/0$;//'$8#:|# )(#'#(\"'#&'#"),l("%;//?#28\"\"6879/0$;//'$8#:}# )(#'#(\"'#&'#"),l("%;//0#;&/'$8\":~\" )(\"'#&'#"),l("%;&/0#;//'$8\":~\" )(\"'#&'#"),l("%;=/T#$;G.) &;K.# &;F0/*;G.) &;K.# &;F&/,$;>/#$+#)(#'#(\"'#&'#"),l('4\x7f""5!7\x80.A &4\x81""5!7\x82.5 &4\x83""5!7\x84.) &;3.# &;.'),l("%%;//Q#;&/H$$;J.# &;K0)*;J.# &;K&/,$;&/#$+$)($'#(#'#(\"'#&'#/\"!&,)"),l("%;//]#;&/T$%$;J.# &;K0)*;J.# &;K&/\"!&,)/1$;&/($8$:\x85$!!)($'#(#'#(\"'#&'#"),l(';..G &2L""6L7M.; &4\x86""5!7\x87./ &4\x83""5!7\x84.# &;3'),l('%2j""6j7k/J#4\x88""5!7\x89.5 &4\x8a""5!7\x8b.) &4\x8c""5!7\x8d/#$+")("\'#&\'#'),l("%;N/M#28\"\"6879/>$;O.\" &\"/0$;S/'$8$:\x8e$ )($'#(#'#(\"'#&'#"),l("%;N/d#28\"\"6879/U$;O.\" &\"/G$;S/>$;_/5$;l.\" &\"/'$8&:\x8f& )(&'#(%'#($'#(#'#(\"'#&'#"),l('%3\x90""5$7\x91.) &3\x92""5#7\x93/\' 8!:\x94!! )'),l('%;P/]#%28""6879/,#;R/#$+")("\'#&\'#." &"/6$2:""6:7;/\'$8#:\x95# )(#\'#("\'#&\'#'),l("$;+.) &;-.# &;Q/2#0/*;+.) &;-.# &;Q&&&#"),l('2<""6<7=.q &2>""6>7?.e &2@""6@7A.Y &2B""6B7C.M &2D""6D7E.A &22""6273.5 &26""6677.) &24""6475'),l('%$;+._ &;-.Y &2<""6<7=.M &2>""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E0e*;+._ &;-.Y &2<""6<7=.M &2>""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E&/& 8!:\x96! )'),l('%;T/J#%28""6879/,#;^/#$+")("\'#&\'#." &"/#$+")("\'#&\'#'),l("%;U.) &;\\.# &;X/& 8!:\x97! )"),l('%$%;V/2#2J""6J7K/#$+")("\'#&\'#0<*%;V/2#2J""6J7K/#$+")("\'#&\'#&/D#;W/;$2J""6J7K." &"/\'$8#:\x98# )(#\'#("\'#&\'#'),l('$4\x99""5!7\x9a/,#0)*4\x99""5!7\x9a&&&#'),l('%4$""5!7%/?#$4\x9b""5!7\x9c0)*4\x9b""5!7\x9c&/#$+")("\'#&\'#'),l('%2l""6l7m/?#;Y/6$2n""6n7o/\'$8#:\x9d# )(#\'#("\'#&\'#'),l('%%;Z/\xb3#28""6879/\xa4$;Z/\x9b$28""6879/\x8c$;Z/\x83$28""6879/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+-)(-\'#(,\'#(+\'#(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0790 &%2\x9e""6\x9e7\x9f/\xa4#;Z/\x9b$28""6879/\x8c$;Z/\x83$28""6879/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+,)(,\'#(+\'#(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u06f9 &%2\x9e""6\x9e7\x9f/\x8c#;Z/\x83$28""6879/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+*)(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u067a &%2\x9e""6\x9e7\x9f/t#;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+()((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0613 &%2\x9e""6\x9e7\x9f/\\#;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+&)(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u05c4 &%2\x9e""6\x9e7\x9f/D#;Z/;$28""6879/,$;[/#$+$)($\'#(#\'#("\'#&\'#.\u058d &%2\x9e""6\x9e7\x9f/,#;[/#$+")("\'#&\'#.\u056e &%2\x9e""6\x9e7\x9f/,#;Z/#$+")("\'#&\'#.\u054f &%;Z/\x9b#2\x9e""6\x9e7\x9f/\x8c$;Z/\x83$28""6879/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$++)(+\'#(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u04c7 &%;Z/\xaa#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x83$2\x9e""6\x9e7\x9f/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+*)(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0430 &%;Z/\xb9#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x92$%28""6879/,#;Z/#$+")("\'#&\'#." &"/k$2\x9e""6\x9e7\x9f/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+))()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u038a &%;Z/\xc8#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xa1$%28""6879/,#;Z/#$+")("\'#&\'#." &"/z$%28""6879/,#;Z/#$+")("\'#&\'#." &"/S$2\x9e""6\x9e7\x9f/D$;Z/;$28""6879/,$;[/#$+()((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u02d5 &%;Z/\xd7#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xb0$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x89$%28""6879/,#;Z/#$+")("\'#&\'#." &"/b$%28""6879/,#;Z/#$+")("\'#&\'#." &"/;$2\x9e""6\x9e7\x9f/,$;[/#$+\')(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0211 &%;Z/\xfe#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xd7$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xb0$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x89$%28""6879/,#;Z/#$+")("\'#&\'#." &"/b$%28""6879/,#;Z/#$+")("\'#&\'#." &"/;$2\x9e""6\x9e7\x9f/,$;Z/#$+()((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0126 &%;Z/\u011c#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xf5$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xce$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xa7$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x80$%28""6879/,#;Z/#$+")("\'#&\'#." &"/Y$%28""6879/,#;Z/#$+")("\'#&\'#." &"/2$2\x9e""6\x9e7\x9f/#$+()((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#/& 8!:\xa0! )'),l('%;#/M#;#." &"/?$;#." &"/1$;#." &"/#$+$)($\'#(#\'#("\'#&\'#'),l("%;Z/;#28\"\"6879/,$;Z/#$+#)(#'#(\"'#&'#.# &;\\"),l("%;]/o#2J\"\"6J7K/`$;]/W$2J\"\"6J7K/H$;]/?$2J\"\"6J7K/0$;]/'$8':\xa1' )(''#(&'#(%'#($'#(#'#(\"'#&'#"),l('%2\xa2""6\xa27\xa3/2#4\xa4""5!7\xa5/#$+")("\'#&\'#.\x98 &%2\xa6""6\xa67\xa7/;#4\xa8""5!7\xa9/,$;!/#$+#)(#\'#("\'#&\'#.j &%2\xaa""6\xaa7\xab/5#;!/,$;!/#$+#)(#\'#("\'#&\'#.B &%4\xac""5!7\xad/,#;!/#$+")("\'#&\'#.# &;!'),l('%%;!." &"/[#;!." &"/M$;!." &"/?$;!." &"/1$;!." &"/#$+%)(%\'#($\'#(#\'#("\'#&\'#/\' 8!:\xae!! )'),l('$%22""6273/,#;`/#$+")("\'#&\'#0<*%22""6273/,#;`/#$+")("\'#&\'#&'),l(";a.A &;b.; &;c.5 &;d./ &;e.) &;f.# &;g"),l('%3\xaf""5*7\xb0/a#3\xb1""5#7\xb2.G &3\xb3""5#7\xb4.; &3\xb5""5$7\xb6./ &3\xb7""5#7\xb8.# &;6/($8":\xb9"! )("\'#&\'#'),l('%3\xba""5%7\xbb/I#3\xbc""5%7\xbd./ &3\xbe""5"7\xbf.# &;6/($8":\xc0"! )("\'#&\'#'),l('%3\xc1""5\'7\xc2/1#;\x8f/($8":\xc3"! )("\'#&\'#'),l('%3\xc4""5$7\xc5/1#;\xef/($8":\xc6"! )("\'#&\'#'),l('%3\xc7""5&7\xc8/1#;T/($8":\xc9"! )("\'#&\'#'),l('%3\xca""5"7\xcb/N#%2>""6>7?/,#;6/#$+")("\'#&\'#." &"/\'$8":\xcc" )("\'#&\'#'),l('%;h/P#%2>""6>7?/,#;i/#$+")("\'#&\'#." &"/)$8":\xcd""! )("\'#&\'#'),l('%$;j/�#*;j&&&#/"!&,)'),l('%$;j/�#*;j&&&#/"!&,)'),l(";k.) &;+.# &;-"),l('2l""6l7m.e &2n""6n7o.Y &24""6475.M &28""6879.A &2<""6<7=.5 &2@""6@7A.) &2B""6B7C'),l('%26""6677/n#;m/e$$%2<""6<7=/,#;m/#$+")("\'#&\'#0<*%2<""6<7=/,#;m/#$+")("\'#&\'#&/#$+#)(#\'#("\'#&\'#'),l('%;n/A#2>""6>7?/2$;o/)$8#:\xce#"" )(#\'#("\'#&\'#'),l("$;p.) &;+.# &;-/2#0/*;p.) &;+.# &;-&&&#"),l("$;p.) &;+.# &;-0/*;p.) &;+.# &;-&"),l('2l""6l7m.e &2n""6n7o.Y &24""6475.M &26""6677.A &28""6879.5 &2@""6@7A.) &2B""6B7C'),l(";\x90.# &;r"),l("%;\x8f/G#;'/>$;s/5$;'/,$;\x84/#$+%)(%'#($'#(#'#(\"'#&'#"),l(";M.# &;t"),l("%;\x7f/E#28\"\"6879/6$;u.# &;x/'$8#:\xcf# )(#'#(\"'#&'#"),l('%;v.# &;w/J#%26""6677/,#;\x83/#$+")("\'#&\'#." &"/#$+")("\'#&\'#'),l('%2\xd0""6\xd07\xd1/:#;\x80/1$;w." &"/#$+#)(#\'#("\'#&\'#'),l('%24""6475/,#;{/#$+")("\'#&\'#'),l("%;z/3#$;y0#*;y&/#$+\")(\"'#&'#"),l(";*.) &;+.# &;-"),l(';+.\x8f &;-.\x89 &22""6273.} &26""6677.q &28""6879.e &2:""6:7;.Y &2<""6<7=.M &2>""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E'),l('%;|/e#$%24""6475/,#;|/#$+")("\'#&\'#0<*%24""6475/,#;|/#$+")("\'#&\'#&/#$+")("\'#&\'#'),l('%$;~0#*;~&/e#$%22""6273/,#;}/#$+")("\'#&\'#0<*%22""6273/,#;}/#$+")("\'#&\'#&/#$+")("\'#&\'#'),l("$;~0#*;~&"),l(';+.w &;-.q &28""6879.e &2:""6:7;.Y &2<""6<7=.M &2>""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E'),l('%%;"/\x87#$;".G &;!.A &2@""6@7A.5 &2F""6F7G.) &2J""6J7K0M*;".G &;!.A &2@""6@7A.5 &2F""6F7G.) &2J""6J7K&/#$+")("\'#&\'#/& 8!:\xd2! )'),l(";\x81.# &;\x82"),l('%%;O/2#2:""6:7;/#$+")("\'#&\'#." &"/,#;S/#$+")("\'#&\'#." &"'),l('$;+.\x83 &;-.} &2B""6B7C.q &2D""6D7E.e &22""6273.Y &28""6879.M &2:""6:7;.A &2<""6<7=.5 &2>""6>7?.) &2@""6@7A/\x8c#0\x89*;+.\x83 &;-.} &2B""6B7C.q &2D""6D7E.e &22""6273.Y &28""6879.M &2:""6:7;.A &2<""6<7=.5 &2>""6>7?.) &2@""6@7A&&&#'),l("$;y0#*;y&"),l('%3\x92""5#7\xd3/q#24""6475/b$$;!/�#*;!&&&#/L$2J""6J7K/=$$;!/�#*;!&&&#/\'$8%:\xd4% )(%\'#($\'#(#\'#("\'#&\'#'),l('2\xd5""6\xd57\xd6'),l('2\xd7""6\xd77\xd8'),l('2\xd9""6\xd97\xda'),l('2\xdb""6\xdb7\xdc'),l('2\xdd""6\xdd7\xde'),l('2\xdf""6\xdf7\xe0'),l('2\xe1""6\xe17\xe2'),l('2\xe3""6\xe37\xe4'),l('2\xe5""6\xe57\xe6'),l('2\xe7""6\xe77\xe8'),l("%;\x85.S &;\x86.M &;\x88.G &;\x89.A &;\x8a.; &;\x8b.5 &;\x8c./ &;\x8d.) &;\x8e.# &;6/& 8!:\xe9! )"),l("%;\x84/G#;'/>$;\x91/5$;'/,$;\x93/#$+%)(%'#($'#(#'#(\"'#&'#"),l("%;\x92/' 8!:\xea!! )"),l("%;!/5#;!/,$;!/#$+#)(#'#(\"'#&'#"),l("%$;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(0G*;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(&/& 8!:\xeb! )"),l("%;\xb5/Y#$%;A/,#;\xb5/#$+\")(\"'#&'#06*%;A/,#;\xb5/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),l('%;9/N#%2:""6:7;/,#;9/#$+")("\'#&\'#." &"/\'$8":\xec" )("\'#&\'#'),l("%;:.c &%;\x97/Y#$%;A/,#;\x97/#$+\")(\"'#&'#06*%;A/,#;\x97/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/& 8!:\xed! )"),l("%;L.# &;\x98/]#$%;B/,#;\x9a/#$+\")(\"'#&'#06*%;B/,#;\x9a/#$+\")(\"'#&'#&/'$8\":\xee\" )(\"'#&'#"),l("%;\x99.\" &\"/>#;@/5$;M/,$;?/#$+$)($'#(#'#(\"'#&'#"),l("%%;6/Y#$%;./,#;6/#$+\")(\"'#&'#06*%;./,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#.# &;H/' 8!:\xef!! )"),l(";\x9b.) &;\x9c.# &;\x9f"),l("%3\xf0\"\"5!7\xf1/:#;$;\xce/5$;./,$;\x8f/#$+%)(%'#($'#(#'#(\"'#&'#"),l("%$;!/�#*;!&&&#/' 8!:\u0149!! )"),l("%;\xd0/]#$%;A/,#;\xd0/#$+\")(\"'#&'#06*%;A/,#;\xd0/#$+\")(\"'#&'#&/'$8\":\u014a\" )(\"'#&'#"),l("%;\x98/]#$%;B/,#;\x9f/#$+\")(\"'#&'#06*%;B/,#;\x9f/#$+\")(\"'#&'#&/'$8\":\u014b\" )(\"'#&'#"),l('%;L.O &;\x98.I &%;@." &"/:#;t/1$;?." &"/#$+#)(#\'#("\'#&\'#/]#$%;B/,#;\x9f/#$+")("\'#&\'#06*%;B/,#;\x9f/#$+")("\'#&\'#&/\'$8":\u014c" )("\'#&\'#'),l("%;\xd3/]#$%;B/,#;\xd4/#$+\")(\"'#&'#06*%;B/,#;\xd4/#$+\")(\"'#&'#&/'$8\":\u014d\" )(\"'#&'#"),l("%;\x95/& 8!:\u014e! )"),l('%3\u014f""5(7\u0150/:#;$;6/5$;;/,$;\xeb/#$+%)(%'#($'#(#'#(\"'#&'#"),l('%3\x92""5#7\xd3.# &;6/\' 8!:\u0189!! )'),l('%3\xb1""5#7\u018a.G &3\xb3""5#7\u018b.; &3\xb7""5#7\u018c./ &3\xb5""5$7\u018d.# &;6/\' 8!:\u018e!! )'),l('%;\xed/D#%;C/,#;\xee/#$+")("\'#&\'#." &"/#$+")("\'#&\'#'),l("%;U.) &;\\.# &;X/& 8!:\u018f! )"),l('%%;!." &"/[#;!." &"/M$;!." &"/?$;!." &"/1$;!." &"/#$+%)(%\'#($\'#(#\'#("\'#&\'#/\' 8!:\u0190!! )'),l('%%;!/?#;!." &"/1$;!." &"/#$+#)(#\'#("\'#&\'#/\' 8!:\u0191!! )'),l(";\xbd"),l('%;\x9d/^#$%;B/,#;\xf2/#$+")("\'#&\'#06*%;B/,#;\xf2/#$+")("\'#&\'#&/($8":\u0192"!!)("\'#&\'#'),l(";\xf3.# &;\x9f"),l('%2\u0193""6\u01937\u0194/L#;""6>7?'),l('%;\xff/b#28""6879/S$;\xfa/J$%2\u01a1""6\u01a17\u01a2/,#;\xeb/#$+")("\'#&\'#." &"/#$+$)($\'#(#\'#("\'#&\'#'),l('%3\u01a3""5%7\u01a4.) &3\u01a5""5$7\u01a6/\' 8!:\u019f!! )'),l('%;\xeb/O#3\xb1""5#7\xb2.6 &3\xb3""5#7\xb4.* &$;+0#*;+&/\'$8":\u01a7" )("\'#&\'#'),l("%;\u0103/\x87#2F\"\"6F7G/x$;\u0102/o$2F\"\"6F7G/`$;\u0102/W$2F\"\"6F7G/H$;\u0102/?$2F\"\"6F7G/0$;\u0104/'$8):\u01a8) )()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#"),l("%;#/>#;#/5$;#/,$;#/#$+$)($'#(#'#(\"'#&'#"),l("%;\u0102/,#;\u0102/#$+\")(\"'#&'#"),l("%;\u0102/5#;\u0102/,$;\u0102/#$+#)(#'#(\"'#&'#"),l("%;\x84/U#;'/L$;\x91/C$;'/:$;\x8f/1$; .\" &\"/#$+&)(&'#(%'#($'#(#'#(\"'#&'#"),l('%2\u01a9""6\u01a97\u01aa.) &2\u01ab""6\u01ab7\u01ac/w#;0/n$;\u0107/e$$%;B/2#;\u0108.# &;\x9f/#$+")("\'#&\'#0<*%;B/2#;\u0108.# &;\x9f/#$+")("\'#&\'#&/#$+$)($\'#(#\'#("\'#&\'#'),l(";\x98.# &;L"),l("%2\u01ad\"\"6\u01ad7\u01ae/5#;-1&&r.indexOf("chrome")<0&&(n=!0);var o={};return n&&(o.modifiers=[e.WebRTC.Modifiers.stripG722]),this.options.ua.uri||(this.anonymous=!0),this.ua=new e.UA({wsServers:this.options.ua.wsServers,uri:this.options.ua.uri,authorizationUser:this.options.ua.authorizationUser,password:this.options.ua.password,displayName:this.options.ua.displayName,traceSip:this.options.ua.traceSip,userAgentString:this.options.ua.userAgentString,register:!0,sessionDescriptionHandlerFactoryOptions:o}),this.state=i.STATUS_NULL,this.logger=this.ua.getLogger("sip.simple"),this.ua.on("registered",function(){this.emit("registered",this.ua)}.bind(this)),this.ua.on("unregistered",function(){this.emit("unregistered",this.ua)}.bind(this)),this.ua.on("failed",function(){this.emit("unregistered",this.ua)}.bind(this)),this.ua.on("invite",function(e){if(this.state!==i.STATUS_NULL&&this.state!==i.STATUS_COMPLETED)return this.logger.warn("Rejecting incoming call. Simple only supports 1 call at a time"),void e.reject();this.session=e,this.setupSession(),this.emit("ringing",this.session)}.bind(this)),this.ua.on("message",function(e){this.emit("message",e)}.bind(this)),this};return s.prototype=Object.create(e.EventEmitter.prototype),s.C=i,s.prototype.call=function(e){if(this.ua&&this.checkRegistration()){if(this.state===i.STATUS_NULL||this.state===i.STATUS_COMPLETED)return this.options.media.remote.audio&&(this.options.media.remote.audio.autoplay=!0),this.options.media.remote.video&&(this.options.media.remote.video.autoplay=!0),this.options.media.local&&this.options.media.local.video&&(this.options.media.local.video.autoplay=!0,this.options.media.local.video.volume=0),this.session=this.ua.invite(e,{sessionDescriptionHandlerOptions:{constraints:{audio:this.audio,video:this.video}}}),this.setupSession(),this.session;this.logger.warn("Cannot make more than a single call with Simple")}else this.logger.warn("A registered UA is required for calling")},s.prototype.answer=function(){if(this.state===i.STATUS_NEW||this.state===i.STATUS_CONNECTING)return this.options.media.remote.audio&&(this.options.media.remote.audio.autoplay=!0),this.options.media.remote.video&&(this.options.media.remote.video.autoplay=!0),this.session.accept({sessionDescriptionHandlerOptions:{constraints:{audio:this.audio,video:this.video}}});this.logger.warn("No call to answer")},s.prototype.reject=function(){if(this.state===i.STATUS_NEW||this.state===i.STATUS_CONNECTING)return this.session.reject();this.logger.warn("Call is already answered")},s.prototype.hangup=function(){if(this.state===i.STATUS_CONNECTED||this.state===i.STATUS_CONNECTING||this.state===i.STATUS_NEW)return this.state!==i.STATUS_CONNECTED?this.session.cancel():this.session.bye();this.logger.warn("No active call to hang up on")},s.prototype.hold=function(){if(this.state===i.STATUS_CONNECTED&&!this.session.local_hold)return this.mute(),this.logger.log("Placing session on hold"),this.session.hold();this.logger.warn("Cannot put call on hold")},s.prototype.unhold=function(){if(this.state===i.STATUS_CONNECTED&&this.session.local_hold)return this.unmute(),this.logger.log("Placing call off hold"),this.session.unhold();this.logger.warn("Cannot unhold a call that is not on hold")},s.prototype.mute=function(){this.state===i.STATUS_CONNECTED?(this.logger.log("Muting Audio"),this.toggleMute(!0)):this.logger.warn("An acitve call is required to mute audio")},s.prototype.unmute=function(){this.state===i.STATUS_CONNECTED?(this.logger.log("Unmuting Audio"),this.toggleMute(!1)):this.logger.warn("An active call is required to unmute audio")},s.prototype.sendDTMF=function(e){this.state===i.STATUS_CONNECTED?(this.logger.log("Sending DTMF tone: "+e),this.session.dtmf(e)):this.logger.warn("An active call is required to send a DTMF tone")},s.prototype.message=function(e,t){this.ua&&this.checkRegistration()?e&&t?this.ua.message(e,t):this.logger.warn("A destination and message are required to send a message"):this.logger.warn("A registered UA is required to send a message")},s.prototype.checkRegistration=function(){return this.anonymous||this.ua&&this.ua.isRegistered()},s.prototype.setupRemoteMedia=function(){var e,i=this.session.sessionDescriptionHandler.peerConnection;i.getReceivers?(e=new t.window.MediaStream,i.getReceivers().forEach(function(t){var i=t.track;i&&e.addTrack(i)})):e=i.getRemoteStreams()[0],this.video?(this.options.media.remote.video.srcObject=e,this.options.media.remote.video.play().catch(function(){this.logger.log("play was rejected")}.bind(this))):this.audio&&(this.options.media.remote.audio.srcObject=e,this.options.media.remote.audio.play().catch(function(){this.logger.log("play was rejected")}.bind(this)))},s.prototype.setupLocalMedia=function(){if(this.video&&this.options.media.local&&this.options.media.local.video){var e,i=this.session.sessionDescriptionHandler.peerConnection;i.getSenders?(e=new t.window.MediaStream,i.getSenders().forEach(function(t){var i=t.track;i&&"video"===i.kind&&e.addTrack(i)})):e=i.getLocalStreams()[0],this.options.media.local.video.srcObject=e,this.options.media.local.video.volume=0,this.options.media.local.video.play()}},s.prototype.cleanupMedia=function(){this.video&&(this.options.media.remote.video.srcObject=null,this.options.media.remote.video.pause(),this.options.media.local&&this.options.media.local.video&&(this.options.media.local.video.srcObject=null,this.options.media.local.video.pause())),this.audio&&(this.options.media.remote.audio.srcObject=null,this.options.media.remote.audio.pause())},s.prototype.setupSession=function(){this.state=i.STATUS_NEW,this.emit("new",this.session),this.session.on("progress",this.onProgress.bind(this)),this.session.on("accepted",this.onAccepted.bind(this)),this.session.on("rejected",this.onEnded.bind(this)),this.session.on("failed",this.onFailed.bind(this)),this.session.on("terminated",this.onEnded.bind(this))},s.prototype.destroyMedia=function(){this.session.sessionDescriptionHandler.close()},s.prototype.toggleMute=function(e){var t=this.session.sessionDescriptionHandler.peerConnection;t.getSenders?t.getSenders().forEach(function(t){t.track&&(t.track.enabled=!e)}):t.getLocalStreams().forEach(function(t){t.getAudioTracks().forEach(function(t){t.enabled=!e}),t.getVideoTracks().forEach(function(t){t.enabled=!e})})},s.prototype.onAccepted=function(){this.state=i.STATUS_CONNECTED,this.emit("connected",this.session),this.setupLocalMedia(),this.setupRemoteMedia(),this.session.sessionDescriptionHandler.on("addTrack",function(){this.logger.log("A track has been added, triggering new remoteMedia setup"),this.setupRemoteMedia()}.bind(this)),this.session.sessionDescriptionHandler.on("addStream",function(){this.logger.log("A stream has been added, trigger new remoteMedia setup"),this.setupRemoteMedia()}.bind(this)),this.session.on("hold",function(){this.emit("hold",this.session)}.bind(this)),this.session.on("unhold",function(){this.emit("unhold",this.session)}.bind(this)),this.session.on("dtmf",function(e){this.emit("dtmf",e)}.bind(this)),this.session.on("bye",this.onEnded.bind(this))},s.prototype.onProgress=function(){this.state=i.STATUS_CONNECTING,this.emit("connecting",this.session)},s.prototype.onFailed=function(){this.onEnded()},s.prototype.onEnded=function(){this.state=i.STATUS_COMPLETED,this.emit("ended",this.session),this.cleanupMedia()},s}}).call(t,i(0))},function(e,t,i){"use strict";(function(t){function s(e,t){if(null!=e){var i=t.charAt(0).toUpperCase()+t.slice(1),s=[t,"webkit"+i,"moz"+i];for(var r in s){var n=e[s[r]];if(n)return n.bind(e)}}}var r=t.window||t;e.exports={WebSocket:r.WebSocket,Transport:i(35),open:r.open,Promise:r.Promise,timers:r,console:r.console||{debug:function(){},log:function(){},warn:function(){},error:function(){}},addEventListener:s(r,"addEventListener"),removeEventListener:s(r,"removeEventListener")}}).call(t,i(0))},function(e,t,i){"use strict";e.exports=function(e,t){var i;return i=function(e,t){this.logger=e.getLogger("sip.transport"),this.ua=e,this.ws=null,this.server=t,this.reconnection_attempts=0,this.closed=!1,this.connected=!1,this.reconnectTimer=null,this.lastTransportError={},this.keepAliveInterval=e.configuration.keepAliveInterval,this.keepAliveTimeout=null,this.keepAliveTimer=null,this.ua.transport=this,this.connect()},i.prototype={send:function(e){var i=e.toString();return this.ws&&this.ws.readyState===t.OPEN?(!0===this.ua.configuration.traceSip&&this.logger.log("sending WebSocket message:\n\n"+i+"\n"),this.ws.send(i),!0):(this.logger.warn("unable to send message, WebSocket is not open"),!1)},sendKeepAlive:function(){if(!this.keepAliveTimeout)return this.keepAliveTimeout=e.Timers.setTimeout(function(){this.ua.emit("keepAliveTimeout")}.bind(this),1e4),this.send("\r\n\r\n")},startSendingKeepAlives:function(){this.keepAliveInterval&&!this.keepAliveTimer&&(this.keepAliveTimer=e.Timers.setTimeout(function(){this.sendKeepAlive(),this.keepAliveTimer=null,this.startSendingKeepAlives()}.bind(this),function(e){var t=.8*e;return 1e3*(Math.random()*(e-t)+t)}(this.keepAliveInterval)))},stopSendingKeepAlives:function(){e.Timers.clearTimeout(this.keepAliveTimer),e.Timers.clearTimeout(this.keepAliveTimeout),this.keepAliveTimer=null,this.keepAliveTimeout=null},disconnect:function(){this.ws&&(e.Timers.clearTimeout(this.reconnectTimer),this.stopSendingKeepAlives(),this.closed=!0,this.logger.log("closing WebSocket "+this.server.ws_uri),this.ws.close(),this.ws=null),null!==this.reconnectTimer&&(e.Timers.clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.ua.emit("disconnected",{transport:this,code:this.lastTransportError.code,reason:this.lastTransportError.reason}))},connect:function(){var e=this;if(this.ws&&(this.ws.readyState===t.OPEN||this.ws.readyState===t.CONNECTING))return this.logger.log("WebSocket "+this.server.ws_uri+" is already connected"),!1;this.ws&&(this.ws.close(),this.ws=null),this.logger.log("connecting to WebSocket "+this.server.ws_uri),this.ua.onTransportConnecting(this,0===this.reconnection_attempts?1:this.reconnection_attempts);try{this.ws=new t(this.server.ws_uri,"sip")}catch(e){this.logger.warn("error connecting to WebSocket "+this.server.ws_uri+": "+e)}this.ws.binaryType="arraybuffer",this.ws.onopen=function(){e.onOpen()},this.ws.onclose=function(t){e.onClose(t),this.onopen=null,this.onclose=null,this.onmessage=null,this.onerror=null},this.ws.onmessage=function(t){e.onMessage(t)},this.ws.onerror=function(t){e.onError(t)}},onOpen:function(){this.connected=!0,this.logger.log("WebSocket "+this.server.ws_uri+" connected"),null!==this.reconnectTimer&&(e.Timers.clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.reconnection_attempts=0,this.closed=!1,this.ua.onTransportConnected(this),this.startSendingKeepAlives()},onClose:function(e){var t=this.connected;this.lastTransportError.code=e.code,this.lastTransportError.reason=e.reason,this.stopSendingKeepAlives(),this.reconnection_attempts>0?(this.logger.log("Reconnection attempt "+this.reconnection_attempts+" failed (code: "+e.code+(e.reason?"| reason: "+e.reason:"")+")"),this.reconnect()):(this.connected=!1,this.logger.log("WebSocket disconnected (code: "+e.code+(e.reason?"| reason: "+e.reason:"")+")"),!1===e.wasClean&&this.logger.warn("WebSocket abrupt disconnection"),!0===t?(this.ua.onTransportClosed(this),this.closed?this.ua.emit("disconnected",{transport:this,code:this.lastTransportError.code,reason:this.lastTransportError.reason}):this.reconnect()):this.ua.onTransportError(this))},onMessage:function(t){var i,s,r=t.data;if("\r\n"===r)return e.Timers.clearTimeout(this.keepAliveTimeout),this.keepAliveTimeout=null,void(!0===this.ua.configuration.traceSip&&this.logger.log("received WebSocket message with CRLF Keep Alive response"));if("string"!=typeof r){try{r=String.fromCharCode.apply(null,new Uint8Array(r))}catch(e){return void this.logger.warn("received WebSocket binary message failed to be converted into string, message discarded")}!0===this.ua.configuration.traceSip&&this.logger.log("received WebSocket binary message:\n\n"+r+"\n")}else!0===this.ua.configuration.traceSip&&this.logger.log("received WebSocket text message:\n\n"+r+"\n");if((i=e.Parser.parseMessage(r,this.ua))&&!(this.ua.status===e.UA.C.STATUS_USER_CLOSED&&i instanceof e.IncomingRequest)&&e.sanityCheck(i,this.ua,this))if(i instanceof e.IncomingRequest)i.transport=this,this.ua.receiveRequest(i);else if(i instanceof e.IncomingResponse)switch(i.method){case e.C.INVITE:(s=this.ua.transactions.ict[i.via_branch])&&s.receiveResponse(i);break;case e.C.ACK:break;default:(s=this.ua.transactions.nict[i.via_branch])&&s.receiveResponse(i)}},onError:function(e){this.logger.warn("WebSocket connection error: "),this.logger.warn(e)},reconnect:function(){var t=this;this.reconnection_attempts+=1,this.reconnection_attempts>this.ua.configuration.wsServerMaxReconnection?(this.logger.warn("maximum reconnection attempts for WebSocket "+this.server.ws_uri),this.ua.onTransportError(this)):1===this.reconnection_attempts?(this.logger.log("Connection to WebSocket "+this.server.ws_uri+" severed, attempting first reconnect"),t.connect()):(this.logger.log("trying to reconnect to WebSocket "+this.server.ws_uri+" (reconnection attempt "+this.reconnection_attempts+")"),this.reconnectTimer=e.Timers.setTimeout(function(){t.connect(),t.reconnectTimer=null},1e3*this.ua.configuration.wsServerReconnectionTimeout))}},i.C={STATUS_READY:0,STATUS_DISCONNECTED:1,STATUS_ERROR:2},i}}])}); \ No newline at end of file diff --git a/dist/sip.js b/dist/sip.js deleted file mode 100644 index 09e96fad6..000000000 --- a/dist/sip.js +++ /dev/null @@ -1,11930 +0,0 @@ -/*! - * - * SIP version 0.9.1 - * Copyright (c) 2014-2017 Junction Networks, Inc - * Homepage: https://sipjs.com - * License: https://sipjs.com/license/ - * - * - * ~~~SIP.js contains substantial portions of JsSIP under the following license~~~ - * Homepage: http://jssip.net - * Copyright (c) 2012-2013 José Luis Millán - Versatica - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * ~~~ end JsSIP license ~~~ - * - * - * - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["SIP"] = factory(); - else - root["SIP"] = factory(); -})(typeof self !== 'undefined' ? self : this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 1); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -var g; - -// This works in non-strict mode -g = (function() { - return this; -})(); - -try { - // This works if eval is allowed (see CSP) - g = g || Function("return this")() || (1,eval)("this"); -} catch(e) { - // This works if the window reference is available - if(typeof window === "object") - g = window; -} - -// g can still be undefined, but nothing to do about it... -// We return undefined, instead of nothing here, so it's -// easier to handle this case. if(!global) { ...} - -module.exports = g; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = __webpack_require__(2)(__webpack_require__(34)); - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * @name SIP - * @namespace - */ - - -module.exports = function (environment) { - - var pkg = __webpack_require__(3), - version = pkg.version, - title = pkg.title; - - var SIP = Object.defineProperties({}, { - version: { - get: function get() { - return version; - } - }, - name: { - get: function get() { - return title; - } - } - }); - - __webpack_require__(4)(SIP, environment); - SIP.LoggerFactory = __webpack_require__(5)(environment.console); - SIP.EventEmitter = __webpack_require__(6)(); - SIP.C = __webpack_require__(8)(SIP.name, SIP.version); - SIP.Exceptions = __webpack_require__(9); - SIP.Timers = __webpack_require__(10)(environment.timers); - SIP.Transport = environment.Transport(SIP, environment.WebSocket); - __webpack_require__(11)(SIP); - __webpack_require__(12)(SIP); - __webpack_require__(13)(SIP); - __webpack_require__(14)(SIP); - __webpack_require__(15)(SIP); - __webpack_require__(16)(SIP); - __webpack_require__(18)(SIP); - __webpack_require__(19)(SIP); - SIP.SessionDescriptionHandler = __webpack_require__(20)(SIP.EventEmitter); - __webpack_require__(21)(SIP); - __webpack_require__(22)(SIP); - __webpack_require__(23)(SIP); - __webpack_require__(25)(SIP); - __webpack_require__(26)(SIP, environment); - __webpack_require__(28)(SIP); - SIP.DigestAuthentication = __webpack_require__(29)(SIP.Utils); - SIP.Grammar = __webpack_require__(30)(SIP); - SIP.WebRTC = { - Modifiers: __webpack_require__(32)(SIP), - Simple: __webpack_require__(33)(SIP) - }; - - return SIP; -}; - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -module.exports = {"name":"sip.js","title":"SIP.js","description":"A simple, intuitive, and powerful JavaScript signaling library","version":"0.9.1","main":"dist/sip.min.js","browser":{"./src/environment.js":"./src/environment_browser.js"},"homepage":"https://sipjs.com","author":"OnSIP (https://sipjs.com/aboutus/)","contributors":[{"url":"https://github.com/onsip/SIP.js/blob/master/THANKS.md"}],"repository":{"type":"git","url":"https://github.com/onsip/SIP.js.git"},"keywords":["sip","websocket","webrtc","library","javascript"],"devDependencies":{"babel-core":"^6.26.0","babel-loader":"^7.1.2","babel-preset-env":"^1.6.1","eslint":"^4.9.0","jasmine-core":"^2.8.0","karma":"^1.7.1","karma-cli":"^1.0.1","karma-jasmine":"^1.1.0","karma-jasmine-html-reporter":"^0.2.2","karma-mocha-reporter":"^2.2.5","karma-phantomjs-launcher":"^1.0.4","karma-webpack":"^2.0.6","pegjs":"^0.10.0","pegjs-loader":"^0.5.4","uglifyjs-webpack-plugin":"^1.0.1","webpack":"^3.8.1"},"engines":{"node":">=4.0"},"license":"MIT","scripts":{"prebuild":"eslint src/*.js src/**/*.js","build":"webpack --progress && cp dist/sip.js dist/sip-$npm_package_version.js && cp dist/sip.min.js dist/sip-$npm_package_version.min.js","browserTest":"sleep 2 && open http://0.0.0.0:9876/debug.html & karma start --reporters kjhtml --no-single-run","commandLineTest":"karma start --reporters mocha --browsers PhantomJS --single-run","buildAndTest":"npm run build && npm run commandLineTest"},"dependencies":{"ws":"^1.0.1"},"optionalDependencies":{"promiscuous":"^0.6.0"}} - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview Utils - */ - -module.exports = function (SIP, environment) { - var Utils; - - Utils = { - - Promise: environment.Promise, - - defer: function defer() { - var deferred = {}; - deferred.promise = new Utils.Promise(function (resolve, reject) { - deferred.resolve = resolve; - deferred.reject = reject; - }); - return deferred; - }, - - reducePromises: function reducePromises(arr, val) { - return arr.reduce(function (acc, fn) { - acc = acc.then(fn); - return acc; - }, SIP.Utils.Promise.resolve(val)); - }, - - augment: function augment(object, constructor, args, override) { - var idx, proto; - - // Add public properties from constructor's prototype onto object - proto = constructor.prototype; - for (idx in proto) { - if (override || object[idx] === undefined) { - object[idx] = proto[idx]; - } - } - - // Construct the object as though it were just created by constructor - constructor.apply(object, args); - }, - - optionsOverride: function optionsOverride(options, winner, loser, isDeprecated, logger, defaultValue) { - if (isDeprecated && options[loser]) { - logger.warn(loser + ' is deprecated, please use ' + winner + ' instead'); - } - - if (options[winner] && options[loser]) { - logger.warn(winner + ' overriding ' + loser); - } - - options[winner] = options[winner] || options[loser] || defaultValue; - }, - - str_utf8_length: function str_utf8_length(string) { - return encodeURIComponent(string).replace(/%[A-F\d]{2}/g, 'U').length; - }, - - generateFakeSDP: function generateFakeSDP(body) { - if (!body) { - return; - } - - var start = body.indexOf('o='); - var end = body.indexOf('\r\n', start); - - return 'v=0\r\n' + body.slice(start, end) + '\r\ns=-\r\nt=0 0\r\nc=IN IP4 0.0.0.0'; - }, - - isFunction: function isFunction(fn) { - if (fn !== undefined) { - return Object.prototype.toString.call(fn) === '[object Function]'; - } else { - return false; - } - }, - - isDecimal: function isDecimal(num) { - return !isNaN(num) && parseFloat(num) === parseInt(num, 10); - }, - - createRandomToken: function createRandomToken(size, base) { - var i, - r, - token = ''; - - base = base || 32; - - for (i = 0; i < size; i++) { - r = Math.random() * base | 0; - token += r.toString(base); - } - - return token; - }, - - newTag: function newTag() { - return SIP.Utils.createRandomToken(SIP.UA.C.TAG_LENGTH); - }, - - // http://stackoverflow.com/users/109538/broofa - newUUID: function newUUID() { - var UUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, - v = c === 'x' ? r : r & 0x3 | 0x8; - return v.toString(16); - }); - - return UUID; - }, - - hostType: function hostType(host) { - if (!host) { - return; - } else { - host = SIP.Grammar.parse(host, 'host'); - if (host !== -1) { - return host.host_type; - } - } - }, - - /** - * Normalize SIP URI. - * NOTE: It does not allow a SIP URI without username. - * Accepts 'sip', 'sips' and 'tel' URIs and convert them into 'sip'. - * Detects the domain part (if given) and properly hex-escapes the user portion. - * If the user portion has only 'tel' number symbols the user portion is clean of 'tel' visual separators. - * @private - * @param {String} target - * @param {String} [domain] - */ - normalizeTarget: function normalizeTarget(target, domain) { - var uri, target_array, target_user, target_domain; - - // If no target is given then raise an error. - if (!target) { - return; - // If a SIP.URI instance is given then return it. - } else if (target instanceof SIP.URI) { - return target; - - // If a string is given split it by '@': - // - Last fragment is the desired domain. - // - Otherwise append the given domain argument. - } else if (typeof target === 'string') { - target_array = target.split('@'); - - switch (target_array.length) { - case 1: - if (!domain) { - return; - } - target_user = target; - target_domain = domain; - break; - case 2: - target_user = target_array[0]; - target_domain = target_array[1]; - break; - default: - target_user = target_array.slice(0, target_array.length - 1).join('@'); - target_domain = target_array[target_array.length - 1]; - } - - // Remove the URI scheme (if present). - target_user = target_user.replace(/^(sips?|tel):/i, ''); - - // Remove 'tel' visual separators if the user portion just contains 'tel' number symbols. - if (/^[\-\.\(\)]*\+?[0-9\-\.\(\)]+$/.test(target_user)) { - target_user = target_user.replace(/[\-\.\(\)]/g, ''); - } - - // Build the complete SIP URI. - target = SIP.C.SIP + ':' + SIP.Utils.escapeUser(target_user) + '@' + target_domain; - // Finally parse the resulting URI. - uri = SIP.URI.parse(target); - - return uri; - } else { - return; - } - }, - - /** - * Hex-escape a SIP URI user. - * @private - * @param {String} user - */ - escapeUser: function escapeUser(user) { - // Don't hex-escape ':' (%3A), '+' (%2B), '?' (%3F"), '/' (%2F). - return encodeURIComponent(decodeURIComponent(user)).replace(/%3A/ig, ':').replace(/%2B/ig, '+').replace(/%3F/ig, '?').replace(/%2F/ig, '/'); - }, - - headerize: function headerize(string) { - var exceptions = { - 'Call-Id': 'Call-ID', - 'Cseq': 'CSeq', - 'Min-Se': 'Min-SE', - 'Rack': 'RAck', - 'Rseq': 'RSeq', - 'Www-Authenticate': 'WWW-Authenticate' - }, - name = string.toLowerCase().replace(/_/g, '-').split('-'), - hname = '', - parts = name.length, - part; - - for (part = 0; part < parts; part++) { - if (part !== 0) { - hname += '-'; - } - hname += name[part].charAt(0).toUpperCase() + name[part].substring(1); - } - if (exceptions[hname]) { - hname = exceptions[hname]; - } - return hname; - }, - - sipErrorCause: function sipErrorCause(status_code) { - var cause; - - for (cause in SIP.C.SIP_ERROR_CAUSES) { - if (SIP.C.SIP_ERROR_CAUSES[cause].indexOf(status_code) !== -1) { - return SIP.C.causes[cause]; - } - } - - return SIP.C.causes.SIP_FAILURE_CODE; - }, - - getReasonPhrase: function getReasonPhrase(code, specific) { - return specific || SIP.C.REASON_PHRASE[code] || ''; - }, - - getReasonHeaderValue: function getReasonHeaderValue(code, reason) { - reason = SIP.Utils.getReasonPhrase(code, reason); - return 'SIP ;cause=' + code + ' ;text="' + reason + '"'; - }, - - getCancelReason: function getCancelReason(code, reason) { - if (code && code < 200 || code > 699) { - throw new TypeError('Invalid status_code: ' + code); - } else if (code) { - return SIP.Utils.getReasonHeaderValue(code, reason); - } - }, - - buildStatusLine: function buildStatusLine(code, reason) { - code = code || null; - reason = reason || null; - - // Validate code and reason values - if (!code || code < 100 || code > 699) { - throw new TypeError('Invalid status_code: ' + code); - } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) { - throw new TypeError('Invalid reason_phrase: ' + reason); - } - - reason = Utils.getReasonPhrase(code, reason); - - return 'SIP/2.0 ' + code + ' ' + reason + '\r\n'; - }, - - /** - * Generate a random Test-Net IP (http://tools.ietf.org/html/rfc5735) - * @private - */ - getRandomTestNetIP: function getRandomTestNetIP() { - function getOctet(from, to) { - return Math.floor(Math.random() * (to - from + 1) + from); - } - return '192.0.2.' + getOctet(1, 254); - }, - - // MD5 (Message-Digest Algorithm) http://www.webtoolkit.info - calculateMD5: function calculateMD5(string) { - function RotateLeft(lValue, iShiftBits) { - return lValue << iShiftBits | lValue >>> 32 - iShiftBits; - } - - function AddUnsigned(lX, lY) { - var lX4, lY4, lX8, lY8, lResult; - lX8 = lX & 0x80000000; - lY8 = lY & 0x80000000; - lX4 = lX & 0x40000000; - lY4 = lY & 0x40000000; - lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF); - if (lX4 & lY4) { - return lResult ^ 0x80000000 ^ lX8 ^ lY8; - } - if (lX4 | lY4) { - if (lResult & 0x40000000) { - return lResult ^ 0xC0000000 ^ lX8 ^ lY8; - } else { - return lResult ^ 0x40000000 ^ lX8 ^ lY8; - } - } else { - return lResult ^ lX8 ^ lY8; - } - } - - function F(x, y, z) { - return x & y | ~x & z; - } - - function G(x, y, z) { - return x & z | y & ~z; - } - - function H(x, y, z) { - return x ^ y ^ z; - } - - function I(x, y, z) { - return y ^ (x | ~z); - } - - function FF(a, b, c, d, x, s, ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - } - - function GG(a, b, c, d, x, s, ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - } - - function HH(a, b, c, d, x, s, ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - } - - function II(a, b, c, d, x, s, ac) { - a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); - return AddUnsigned(RotateLeft(a, s), b); - } - - function ConvertToWordArray(string) { - var lWordCount; - var lMessageLength = string.length; - var lNumberOfWords_temp1 = lMessageLength + 8; - var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - lNumberOfWords_temp1 % 64) / 64; - var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16; - var lWordArray = Array(lNumberOfWords - 1); - var lBytePosition = 0; - var lByteCount = 0; - while (lByteCount < lMessageLength) { - lWordCount = (lByteCount - lByteCount % 4) / 4; - lBytePosition = lByteCount % 4 * 8; - lWordArray[lWordCount] = lWordArray[lWordCount] | string.charCodeAt(lByteCount) << lBytePosition; - lByteCount++; - } - lWordCount = (lByteCount - lByteCount % 4) / 4; - lBytePosition = lByteCount % 4 * 8; - lWordArray[lWordCount] = lWordArray[lWordCount] | 0x80 << lBytePosition; - lWordArray[lNumberOfWords - 2] = lMessageLength << 3; - lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; - return lWordArray; - } - - function WordToHex(lValue) { - var WordToHexValue = "", - WordToHexValue_temp = "", - lByte, - lCount; - for (lCount = 0; lCount <= 3; lCount++) { - lByte = lValue >>> lCount * 8 & 255; - WordToHexValue_temp = "0" + lByte.toString(16); - WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2); - } - return WordToHexValue; - } - - function Utf8Encode(string) { - string = string.replace(/\r\n/g, "\n"); - var utftext = ""; - - for (var n = 0; n < string.length; n++) { - var c = string.charCodeAt(n); - - if (c < 128) { - utftext += String.fromCharCode(c); - } else if (c > 127 && c < 2048) { - utftext += String.fromCharCode(c >> 6 | 192); - utftext += String.fromCharCode(c & 63 | 128); - } else { - utftext += String.fromCharCode(c >> 12 | 224); - utftext += String.fromCharCode(c >> 6 & 63 | 128); - utftext += String.fromCharCode(c & 63 | 128); - } - } - return utftext; - } - - var x = []; - var k, AA, BB, CC, DD, a, b, c, d; - var S11 = 7, - S12 = 12, - S13 = 17, - S14 = 22; - var S21 = 5, - S22 = 9, - S23 = 14, - S24 = 20; - var S31 = 4, - S32 = 11, - S33 = 16, - S34 = 23; - var S41 = 6, - S42 = 10, - S43 = 15, - S44 = 21; - - string = Utf8Encode(string); - - x = ConvertToWordArray(string); - - a = 0x67452301;b = 0xEFCDAB89;c = 0x98BADCFE;d = 0x10325476; - - for (k = 0; k < x.length; k += 16) { - AA = a;BB = b;CC = c;DD = d; - a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478); - d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756); - c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB); - b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE); - a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF); - d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A); - c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613); - b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501); - a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8); - d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF); - c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1); - b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE); - a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122); - d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193); - c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E); - b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821); - a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562); - d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340); - c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51); - b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA); - a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D); - d = GG(d, a, b, c, x[k + 10], S22, 0x2441453); - c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681); - b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8); - a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6); - d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6); - c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87); - b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED); - a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905); - d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8); - c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9); - b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A); - a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942); - d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681); - c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122); - b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C); - a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44); - d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9); - c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60); - b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70); - a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6); - d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA); - c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085); - b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05); - a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039); - d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5); - c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8); - b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665); - a = II(a, b, c, d, x[k + 0], S41, 0xF4292244); - d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97); - c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7); - b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039); - a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3); - d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92); - c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D); - b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1); - a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F); - d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0); - c = II(c, d, a, b, x[k + 6], S43, 0xA3014314); - b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1); - a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82); - d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235); - c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB); - b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391); - a = AddUnsigned(a, AA); - b = AddUnsigned(b, BB); - c = AddUnsigned(c, CC); - d = AddUnsigned(d, DD); - } - - var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d); - - return temp.toLowerCase(); - } - }; - - SIP.Utils = Utils; -}; - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var levels = { - 'error': 0, - 'warn': 1, - 'log': 2, - 'debug': 3 -}; - -module.exports = function (console) { - - var LoggerFactory = function LoggerFactory() { - var logger, - level = 2, - builtinEnabled = true, - connector = null; - - this.loggers = {}; - - logger = this.getLogger('sip.loggerfactory'); - - Object.defineProperties(this, { - builtinEnabled: { - get: function get() { - return builtinEnabled; - }, - set: function set(value) { - if (typeof value === 'boolean') { - builtinEnabled = value; - } else { - logger.error('invalid "builtinEnabled" parameter value: ' + JSON.stringify(value)); - } - } - }, - - level: { - get: function get() { - return level; - }, - set: function set(value) { - if (value >= 0 && value <= 3) { - level = value; - } else if (value > 3) { - level = 3; - } else if (levels.hasOwnProperty(value)) { - level = levels[value]; - } else { - logger.error('invalid "level" parameter value: ' + JSON.stringify(value)); - } - } - }, - - connector: { - get: function get() { - return connector; - }, - set: function set(value) { - if (value === null || value === "" || value === undefined) { - connector = null; - } else if (typeof value === 'function') { - connector = value; - } else { - logger.error('invalid "connector" parameter value: ' + JSON.stringify(value)); - } - } - } - }); - }; - - LoggerFactory.prototype.print = function (target, category, label, content) { - if (typeof content === 'string') { - var prefix = [new Date(), category]; - if (label) { - prefix.push(label); - } - content = prefix.concat(content).join(' | '); - } - target.call(console, content); - }; - - function Logger(logger, category, label) { - this.logger = logger; - this.category = category; - this.label = label; - } - - Object.keys(levels).forEach(function (targetName) { - Logger.prototype[targetName] = function (content) { - this.logger[targetName](this.category, this.label, content); - }; - - LoggerFactory.prototype[targetName] = function (category, label, content) { - if (this.level >= levels[targetName]) { - if (this.builtinEnabled) { - this.print(console[targetName], category, label, content); - } - - if (this.connector) { - this.connector(targetName, category, label, content); - } - } - }; - }); - - LoggerFactory.prototype.getLogger = function (category, label) { - var logger; - - if (label && this.level === 3) { - return new Logger(this, category, label); - } else if (this.loggers[category]) { - return this.loggers[category]; - } else { - logger = new Logger(this, category); - this.loggers[category] = logger; - return logger; - } - }; - - return LoggerFactory; -}; - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var NodeEventEmitter = __webpack_require__(7).EventEmitter; - -module.exports = function () { - - // Don't use `new SIP.EventEmitter()` for inheriting. - // Use Object.create(SIP.EventEmitter.prototoype); - function EventEmitter() { - NodeEventEmitter.call(this); - } - - EventEmitter.prototype = Object.create(NodeEventEmitter.prototype, { - constructor: { - value: EventEmitter, - enumerable: false, - writable: true, - configurable: true - } - }); - - return EventEmitter; -}; - -/***/ }), -/* 7 */ -/***/ (function(module, exports) { - -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } else { - // At least give some kind of context to the user - var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); - err.context = er; - throw err; - } - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - } else if (isObject(handler)) { - args = Array.prototype.slice.call(arguments, 1); - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - - if (isFunction(evlistener)) - return 1; - else if (evlistener) - return evlistener.length; - } - return 0; -}; - -EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); -}; - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isUndefined(arg) { - return arg === void 0; -} - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Constants - */ - -/** - * SIP Constants. - * @augments SIP - */ - -module.exports = function (name, version) { - return { - USER_AGENT: name + '/' + version, - - // SIP scheme - SIP: 'sip', - SIPS: 'sips', - - // End and Failure causes - causes: { - // Generic error causes - CONNECTION_ERROR: 'Connection Error', - REQUEST_TIMEOUT: 'Request Timeout', - SIP_FAILURE_CODE: 'SIP Failure Code', - INTERNAL_ERROR: 'Internal Error', - - // SIP error causes - BUSY: 'Busy', - REJECTED: 'Rejected', - REDIRECTED: 'Redirected', - UNAVAILABLE: 'Unavailable', - NOT_FOUND: 'Not Found', - ADDRESS_INCOMPLETE: 'Address Incomplete', - INCOMPATIBLE_SDP: 'Incompatible SDP', - AUTHENTICATION_ERROR: 'Authentication Error', - DIALOG_ERROR: 'Dialog Error', - - // Session error causes - WEBRTC_NOT_SUPPORTED: 'WebRTC Not Supported', - WEBRTC_ERROR: 'WebRTC Error', - CANCELED: 'Canceled', - NO_ANSWER: 'No Answer', - EXPIRES: 'Expires', - NO_ACK: 'No ACK', - NO_PRACK: 'No PRACK', - USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access', - BAD_MEDIA_DESCRIPTION: 'Bad Media Description', - RTP_TIMEOUT: 'RTP Timeout' - }, - - supported: { - UNSUPPORTED: 'none', - SUPPORTED: 'supported', - REQUIRED: 'required' - }, - - SIP_ERROR_CAUSES: { - REDIRECTED: [300, 301, 302, 305, 380], - BUSY: [486, 600], - REJECTED: [403, 603], - NOT_FOUND: [404, 604], - UNAVAILABLE: [480, 410, 408, 430], - ADDRESS_INCOMPLETE: [484], - INCOMPATIBLE_SDP: [488, 606], - AUTHENTICATION_ERROR: [401, 407] - }, - - // SIP Methods - ACK: 'ACK', - BYE: 'BYE', - CANCEL: 'CANCEL', - INFO: 'INFO', - INVITE: 'INVITE', - MESSAGE: 'MESSAGE', - NOTIFY: 'NOTIFY', - OPTIONS: 'OPTIONS', - REGISTER: 'REGISTER', - UPDATE: 'UPDATE', - SUBSCRIBE: 'SUBSCRIBE', - REFER: 'REFER', - PRACK: 'PRACK', - - /* SIP Response Reasons - * DOC: http://www.iana.org/assignments/sip-parameters - * Copied from https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/constants.rb#L7 - */ - REASON_PHRASE: { - 100: 'Trying', - 180: 'Ringing', - 181: 'Call Is Being Forwarded', - 182: 'Queued', - 183: 'Session Progress', - 199: 'Early Dialog Terminated', // draft-ietf-sipcore-199 - 200: 'OK', - 202: 'Accepted', // RFC 3265 - 204: 'No Notification', //RFC 5839 - 300: 'Multiple Choices', - 301: 'Moved Permanently', - 302: 'Moved Temporarily', - 305: 'Use Proxy', - 380: 'Alternative Service', - 400: 'Bad Request', - 401: 'Unauthorized', - 402: 'Payment Required', - 403: 'Forbidden', - 404: 'Not Found', - 405: 'Method Not Allowed', - 406: 'Not Acceptable', - 407: 'Proxy Authentication Required', - 408: 'Request Timeout', - 410: 'Gone', - 412: 'Conditional Request Failed', // RFC 3903 - 413: 'Request Entity Too Large', - 414: 'Request-URI Too Long', - 415: 'Unsupported Media Type', - 416: 'Unsupported URI Scheme', - 417: 'Unknown Resource-Priority', // RFC 4412 - 420: 'Bad Extension', - 421: 'Extension Required', - 422: 'Session Interval Too Small', // RFC 4028 - 423: 'Interval Too Brief', - 428: 'Use Identity Header', // RFC 4474 - 429: 'Provide Referrer Identity', // RFC 3892 - 430: 'Flow Failed', // RFC 5626 - 433: 'Anonymity Disallowed', // RFC 5079 - 436: 'Bad Identity-Info', // RFC 4474 - 437: 'Unsupported Certificate', // RFC 4744 - 438: 'Invalid Identity Header', // RFC 4744 - 439: 'First Hop Lacks Outbound Support', // RFC 5626 - 440: 'Max-Breadth Exceeded', // RFC 5393 - 469: 'Bad Info Package', // draft-ietf-sipcore-info-events - 470: 'Consent Needed', // RFC 5360 - 478: 'Unresolvable Destination', // Custom code copied from Kamailio. - 480: 'Temporarily Unavailable', - 481: 'Call/Transaction Does Not Exist', - 482: 'Loop Detected', - 483: 'Too Many Hops', - 484: 'Address Incomplete', - 485: 'Ambiguous', - 486: 'Busy Here', - 487: 'Request Terminated', - 488: 'Not Acceptable Here', - 489: 'Bad Event', // RFC 3265 - 491: 'Request Pending', - 493: 'Undecipherable', - 494: 'Security Agreement Required', // RFC 3329 - 500: 'Internal Server Error', - 501: 'Not Implemented', - 502: 'Bad Gateway', - 503: 'Service Unavailable', - 504: 'Server Time-out', - 505: 'Version Not Supported', - 513: 'Message Too Large', - 580: 'Precondition Failure', // RFC 3312 - 600: 'Busy Everywhere', - 603: 'Decline', - 604: 'Does Not Exist Anywhere', - 606: 'Not Acceptable' - }, - - /* SIP Option Tags - * DOC: http://www.iana.org/assignments/sip-parameters/sip-parameters.xhtml#sip-parameters-4 - */ - OPTION_TAGS: { - '100rel': true, // RFC 3262 - 199: true, // RFC 6228 - answermode: true, // RFC 5373 - 'early-session': true, // RFC 3959 - eventlist: true, // RFC 4662 - explicitsub: true, // RFC-ietf-sipcore-refer-explicit-subscription-03 - 'from-change': true, // RFC 4916 - 'geolocation-http': true, // RFC 6442 - 'geolocation-sip': true, // RFC 6442 - gin: true, // RFC 6140 - gruu: true, // RFC 5627 - histinfo: true, // RFC 7044 - ice: true, // RFC 5768 - join: true, // RFC 3911 - 'multiple-refer': true, // RFC 5368 - norefersub: true, // RFC 4488 - nosub: true, // RFC-ietf-sipcore-refer-explicit-subscription-03 - outbound: true, // RFC 5626 - path: true, // RFC 3327 - policy: true, // RFC 6794 - precondition: true, // RFC 3312 - pref: true, // RFC 3840 - privacy: true, // RFC 3323 - 'recipient-list-invite': true, // RFC 5366 - 'recipient-list-message': true, // RFC 5365 - 'recipient-list-subscribe': true, // RFC 5367 - replaces: true, // RFC 3891 - 'resource-priority': true, // RFC 4412 - 'sdp-anat': true, // RFC 4092 - 'sec-agree': true, // RFC 3329 - tdialog: true, // RFC 4538 - timer: true, // RFC 4028 - uui: true // RFC 7433 - } - }; -}; - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview Exceptions - */ - -/** - * SIP Exceptions. - * @augments SIP - */ - -module.exports = { - ConfigurationError: function () { - var exception = function exception(parameter, value) { - this.code = 1; - this.name = 'CONFIGURATION_ERROR'; - this.parameter = parameter; - this.value = value; - this.message = !this.value ? 'Missing parameter: ' + this.parameter : 'Invalid value ' + JSON.stringify(this.value) + ' for parameter "' + this.parameter + '"'; - }; - exception.prototype = new Error(); - return exception; - }(), - - InvalidStateError: function () { - var exception = function exception(status) { - this.code = 2; - this.name = 'INVALID_STATE_ERROR'; - this.status = status; - this.message = 'Invalid status: ' + status; - }; - exception.prototype = new Error(); - return exception; - }(), - - NotSupportedError: function () { - var exception = function exception(message) { - this.code = 3; - this.name = 'NOT_SUPPORTED_ERROR'; - this.message = message; - }; - exception.prototype = new Error(); - return exception; - }(), - - GetDescriptionError: function () { - var exception = function exception(message) { - this.code = 4; - this.name = 'GET_DESCRIPTION_ERROR'; - this.message = message; - }; - exception.prototype = new Error(); - return exception; - }(), - - RenegotiationError: function () { - var exception = function exception(message) { - this.code = 5; - this.name = 'RENEGOTIATION_ERROR'; - this.message = message; - }; - exception.prototype = new Error(); - return exception; - }() -}; - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP TIMERS - */ - -/** - * @augments SIP - */ - -var T1 = 500, - T2 = 4000, - T4 = 5000; -module.exports = function (timers) { - var Timers = { - T1: T1, - T2: T2, - T4: T4, - TIMER_B: 64 * T1, - TIMER_D: 0 * T1, - TIMER_F: 64 * T1, - TIMER_H: 64 * T1, - TIMER_I: 0 * T1, - TIMER_J: 0 * T1, - TIMER_K: 0 * T4, - TIMER_L: 64 * T1, - TIMER_M: 64 * T1, - TIMER_N: 64 * T1, - PROVISIONAL_RESPONSE_INTERVAL: 60000 // See RFC 3261 Section 13.3.1.1 - }; - - ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval'].forEach(function (name) { - // can't just use timers[name].bind(timers) since it bypasses jasmine's - // clock-mocking - Timers[name] = function () { - return timers[name].apply(timers, arguments); - }; - }); - - return Timers; -}; - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Message Parser - */ - -/** - * Extract and parse every header of a SIP message. - * @augments SIP - * @namespace - */ - -module.exports = function (SIP) { - var Parser; - - function getHeader(data, headerStart) { - var - // 'start' position of the header. - start = headerStart, - - // 'end' position of the header. - end = 0, - - // 'partial end' position of the header. - partialEnd = 0; - - //End of message. - if (data.substring(start, start + 2).match(/(^\r\n)/)) { - return -2; - } - - while (end === 0) { - // Partial End of Header. - partialEnd = data.indexOf('\r\n', start); - - // 'indexOf' returns -1 if the value to be found never occurs. - if (partialEnd === -1) { - return partialEnd; - } - - if (!data.substring(partialEnd + 2, partialEnd + 4).match(/(^\r\n)/) && data.charAt(partialEnd + 2).match(/(^\s+)/)) { - // Not the end of the message. Continue from the next position. - start = partialEnd + 2; - } else { - end = partialEnd; - } - } - - return end; - } - - function parseHeader(message, data, headerStart, headerEnd) { - var header, - idx, - length, - parsed, - hcolonIndex = data.indexOf(':', headerStart), - headerName = data.substring(headerStart, hcolonIndex).trim(), - headerValue = data.substring(hcolonIndex + 1, headerEnd).trim(); - - // If header-field is well-known, parse it. - switch (headerName.toLowerCase()) { - case 'via': - case 'v': - message.addHeader('via', headerValue); - if (message.getHeaders('via').length === 1) { - parsed = message.parseHeader('Via'); - if (parsed) { - message.via = parsed; - message.via_branch = parsed.branch; - } - } else { - parsed = 0; - } - break; - case 'from': - case 'f': - message.setHeader('from', headerValue); - parsed = message.parseHeader('from'); - if (parsed) { - message.from = parsed; - message.from_tag = parsed.getParam('tag'); - } - break; - case 'to': - case 't': - message.setHeader('to', headerValue); - parsed = message.parseHeader('to'); - if (parsed) { - message.to = parsed; - message.to_tag = parsed.getParam('tag'); - } - break; - case 'record-route': - parsed = SIP.Grammar.parse(headerValue, 'Record_Route'); - - if (parsed === -1) { - parsed = undefined; - break; - } - - length = parsed.length; - for (idx = 0; idx < length; idx++) { - header = parsed[idx]; - message.addHeader('record-route', headerValue.substring(header.position, header.offset)); - message.headers['Record-Route'][message.getHeaders('record-route').length - 1].parsed = header.parsed; - } - break; - case 'call-id': - case 'i': - message.setHeader('call-id', headerValue); - parsed = message.parseHeader('call-id'); - if (parsed) { - message.call_id = headerValue; - } - break; - case 'contact': - case 'm': - parsed = SIP.Grammar.parse(headerValue, 'Contact'); - - if (parsed === -1) { - parsed = undefined; - break; - } - - length = parsed.length; - for (idx = 0; idx < length; idx++) { - header = parsed[idx]; - message.addHeader('contact', headerValue.substring(header.position, header.offset)); - message.headers['Contact'][message.getHeaders('contact').length - 1].parsed = header.parsed; - } - break; - case 'content-length': - case 'l': - message.setHeader('content-length', headerValue); - parsed = message.parseHeader('content-length'); - break; - case 'content-type': - case 'c': - message.setHeader('content-type', headerValue); - parsed = message.parseHeader('content-type'); - break; - case 'cseq': - message.setHeader('cseq', headerValue); - parsed = message.parseHeader('cseq'); - if (parsed) { - message.cseq = parsed.value; - } - if (message instanceof SIP.IncomingResponse) { - message.method = parsed.method; - } - break; - case 'max-forwards': - message.setHeader('max-forwards', headerValue); - parsed = message.parseHeader('max-forwards'); - break; - case 'www-authenticate': - message.setHeader('www-authenticate', headerValue); - parsed = message.parseHeader('www-authenticate'); - break; - case 'proxy-authenticate': - message.setHeader('proxy-authenticate', headerValue); - parsed = message.parseHeader('proxy-authenticate'); - break; - case 'refer-to': - case 'r': - message.setHeader('refer-to', headerValue); - parsed = message.parseHeader('refer-to'); - if (parsed) { - message.refer_to = parsed; - } - break; - default: - // Do not parse this header. - message.setHeader(headerName, headerValue); - parsed = 0; - } - - if (parsed === undefined) { - return { - error: 'error parsing header "' + headerName + '"' - }; - } else { - return true; - } - } - - /** Parse SIP Message - * @function - * @param {String} message SIP message. - * @param {Object} logger object. - * @returns {SIP.IncomingRequest|SIP.IncomingResponse|undefined} - */ - Parser = {}; - Parser.parseMessage = function (data, ua) { - var message, - firstLine, - contentLength, - bodyStart, - parsed, - headerStart = 0, - headerEnd = data.indexOf('\r\n'), - logger = ua.getLogger('sip.parser'); - - if (headerEnd === -1) { - logger.warn('no CRLF found, not a SIP message, discarded'); - return; - } - - // Parse first line. Check if it is a Request or a Reply. - firstLine = data.substring(0, headerEnd); - parsed = SIP.Grammar.parse(firstLine, 'Request_Response'); - - if (parsed === -1) { - logger.warn('error parsing first line of SIP message: "' + firstLine + '"'); - return; - } else if (!parsed.status_code) { - message = new SIP.IncomingRequest(ua); - message.method = parsed.method; - message.ruri = parsed.uri; - } else { - message = new SIP.IncomingResponse(ua); - message.status_code = parsed.status_code; - message.reason_phrase = parsed.reason_phrase; - } - - message.data = data; - headerStart = headerEnd + 2; - - /* Loop over every line in data. Detect the end of each header and parse - * it or simply add to the headers collection. - */ - while (true) { - headerEnd = getHeader(data, headerStart); - - // The SIP message has normally finished. - if (headerEnd === -2) { - bodyStart = headerStart + 2; - break; - } - // data.indexOf returned -1 due to a malformed message. - else if (headerEnd === -1) { - logger.error('malformed message'); - return; - } - - parsed = parseHeader(message, data, headerStart, headerEnd); - - if (parsed !== true) { - logger.error(parsed.error); - return; - } - - headerStart = headerEnd + 2; - } - - /* RFC3261 18.3. - * If there are additional bytes in the transport packet - * beyond the end of the body, they MUST be discarded. - */ - if (message.hasHeader('content-length')) { - contentLength = message.getHeader('content-length'); - message.body = data.substr(bodyStart, contentLength); - } else { - message.body = data.substring(bodyStart); - } - - return message; - }; - - SIP.Parser = Parser; -}; - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Message - */ - -module.exports = function (SIP) { - var OutgoingRequest, IncomingMessage, IncomingRequest, IncomingResponse; - - function getSupportedHeader(request) { - var allowUnregistered = request.ua.configuration.hackAllowUnregisteredOptionTags; - var optionTags = []; - var optionTagSet = {}; - - if (request.method === SIP.C.REGISTER) { - optionTags.push('path', 'gruu'); - } else if (request.method === SIP.C.INVITE && (request.ua.contact.pub_gruu || request.ua.contact.temp_gruu)) { - optionTags.push('gruu'); - } - - if (request.ua.configuration.rel100 === SIP.C.supported.SUPPORTED) { - optionTags.push('100rel'); - } - if (request.ua.configuration.replaces === SIP.C.supported.SUPPORTED) { - optionTags.push('replaces'); - } - - optionTags.push('outbound'); - - optionTags = optionTags.concat(request.ua.configuration.extraSupported); - - optionTags = optionTags.filter(function (optionTag) { - var registered = SIP.C.OPTION_TAGS[optionTag]; - var unique = !optionTagSet[optionTag]; - optionTagSet[optionTag] = true; - return (registered || allowUnregistered) && unique; - }); - - return 'Supported: ' + optionTags.join(', ') + '\r\n'; - } - - /** - * @augments SIP - * @class Class for outgoing SIP request. - * @param {String} method request method - * @param {String} ruri request uri - * @param {SIP.UA} ua - * @param {Object} params parameters that will have priority over ua.configuration parameters: - *
- * - cseq, call_id, from_tag, from_uri, from_displayName, to_uri, to_tag, route_set - * @param {Object} [headers] extra headers - * @param {String} [body] - */ - OutgoingRequest = function OutgoingRequest(method, ruri, ua, params, extraHeaders, body) { - var to, from, call_id, cseq, to_uri, from_uri; - - params = params || {}; - - // Mandatory parameters check - if (!method || !ruri || !ua) { - return null; - } - - this.logger = ua.getLogger('sip.sipmessage'); - this.ua = ua; - this.headers = {}; - this.method = method; - this.ruri = ruri; - this.body = body; - this.extraHeaders = (extraHeaders || []).slice(); - this.statusCode = params.status_code; - this.reasonPhrase = params.reason_phrase; - - // Fill the Common SIP Request Headers - - // Route - if (params.route_set) { - this.setHeader('route', params.route_set); - } else if (ua.configuration.usePreloadedRoute) { - this.setHeader('route', ua.transport.server.sip_uri); - } - - // Via - // Empty Via header. Will be filled by the client transaction. - this.setHeader('via', ''); - - // Max-Forwards - this.setHeader('max-forwards', SIP.UA.C.MAX_FORWARDS); - - // To - to_uri = params.to_uri || ruri; - to = params.to_displayName || params.to_displayName === 0 ? '"' + params.to_displayName + '" ' : ''; - to += '<' + (to_uri && to_uri.toRaw ? to_uri.toRaw() : to_uri) + '>'; - to += params.to_tag ? ';tag=' + params.to_tag : ''; - this.to = new SIP.NameAddrHeader.parse(to); - this.setHeader('to', to); - - // From - from_uri = params.from_uri || ua.configuration.uri; - if (params.from_displayName || params.from_displayName === 0) { - from = '"' + params.from_displayName + '" '; - } else if (ua.configuration.displayName) { - from = '"' + ua.configuration.displayName + '" '; - } else { - from = ''; - } - from += '<' + (from_uri && from_uri.toRaw ? from_uri.toRaw() : from_uri) + '>;tag='; - from += params.from_tag || SIP.Utils.newTag(); - this.from = new SIP.NameAddrHeader.parse(from); - this.setHeader('from', from); - - // Call-ID - call_id = params.call_id || ua.configuration.sipjsId + SIP.Utils.createRandomToken(15); - this.call_id = call_id; - this.setHeader('call-id', call_id); - - // CSeq - cseq = params.cseq || Math.floor(Math.random() * 10000); - this.cseq = cseq; - this.setHeader('cseq', cseq + ' ' + method); - }; - - OutgoingRequest.prototype = { - /** - * Replace the the given header by the given value. - * @param {String} name header name - * @param {String | Array} value header value - */ - setHeader: function setHeader(name, value) { - this.headers[SIP.Utils.headerize(name)] = value instanceof Array ? value : [value]; - }, - - /** - * Get the value of the given header name at the given position. - * @param {String} name header name - * @returns {String|undefined} Returns the specified header, undefined if header doesn't exist. - */ - getHeader: function getHeader(name) { - var regexp, - idx, - length = this.extraHeaders.length, - header = this.headers[SIP.Utils.headerize(name)]; - - if (header) { - if (header[0]) { - return header[0]; - } - } else { - regexp = new RegExp('^\\s*' + name + '\\s*:', 'i'); - for (idx = 0; idx < length; idx++) { - header = this.extraHeaders[idx]; - if (regexp.test(header)) { - return header.substring(header.indexOf(':') + 1).trim(); - } - } - } - - return; - }, - - /** - * Get the header/s of the given name. - * @param {String} name header name - * @returns {Array} Array with all the headers of the specified name. - */ - getHeaders: function getHeaders(name) { - var idx, - length, - regexp, - header = this.headers[SIP.Utils.headerize(name)], - result = []; - - if (header) { - length = header.length; - for (idx = 0; idx < length; idx++) { - result.push(header[idx]); - } - return result; - } else { - length = this.extraHeaders.length; - regexp = new RegExp('^\\s*' + name + '\\s*:', 'i'); - for (idx = 0; idx < length; idx++) { - header = this.extraHeaders[idx]; - if (regexp.test(header)) { - result.push(header.substring(header.indexOf(':') + 1).trim()); - } - } - return result; - } - }, - - /** - * Verify the existence of the given header. - * @param {String} name header name - * @returns {boolean} true if header with given name exists, false otherwise - */ - hasHeader: function hasHeader(name) { - var regexp, - idx, - length = this.extraHeaders.length; - - if (this.headers[SIP.Utils.headerize(name)]) { - return true; - } else { - regexp = new RegExp('^\\s*' + name + '\\s*:', 'i'); - for (idx = 0; idx < length; idx++) { - if (regexp.test(this.extraHeaders[idx])) { - return true; - } - } - } - - return false; - }, - - toString: function toString() { - var msg = '', - header, - length, - idx; - - msg += this.method + ' ' + (this.ruri.toRaw ? this.ruri.toRaw() : this.ruri) + ' SIP/2.0\r\n'; - - for (header in this.headers) { - length = this.headers[header].length; - for (idx = 0; idx < length; idx++) { - msg += header + ': ' + this.headers[header][idx] + '\r\n'; - } - } - - length = this.extraHeaders.length; - for (idx = 0; idx < length; idx++) { - msg += this.extraHeaders[idx].trim() + '\r\n'; - } - - msg += getSupportedHeader(this); - msg += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n'; - - if (this.body) { - if (typeof this.body === 'string') { - length = SIP.Utils.str_utf8_length(this.body); - msg += 'Content-Length: ' + length + '\r\n\r\n'; - msg += this.body; - } else { - if (this.body.body && this.body.contentType) { - length = SIP.Utils.str_utf8_length(this.body.body); - msg += 'Content-Type: ' + this.body.contentType + '\r\n'; - msg += 'Content-Length: ' + length + '\r\n\r\n'; - msg += this.body.body; - } else { - msg += 'Content-Length: ' + 0 + '\r\n\r\n'; - } - } - } else { - msg += 'Content-Length: ' + 0 + '\r\n\r\n'; - } - - return msg; - } - }; - - /** - * @augments SIP - * @class Class for incoming SIP message. - */ - IncomingMessage = function IncomingMessage() { - this.data = null; - this.headers = null; - this.method = null; - this.via = null; - this.via_branch = null; - this.call_id = null; - this.cseq = null; - this.from = null; - this.from_tag = null; - this.to = null; - this.to_tag = null; - this.body = null; - }; - - IncomingMessage.prototype = { - /** - * Insert a header of the given name and value into the last position of the - * header array. - * @param {String} name header name - * @param {String} value header value - */ - addHeader: function addHeader(name, value) { - var header = { raw: value }; - - name = SIP.Utils.headerize(name); - - if (this.headers[name]) { - this.headers[name].push(header); - } else { - this.headers[name] = [header]; - } - }, - - /** - * Get the value of the given header name at the given position. - * @param {String} name header name - * @returns {String|undefined} Returns the specified header, null if header doesn't exist. - */ - getHeader: function getHeader(name) { - var header = this.headers[SIP.Utils.headerize(name)]; - - if (header) { - if (header[0]) { - return header[0].raw; - } - } else { - return; - } - }, - - /** - * Get the header/s of the given name. - * @param {String} name header name - * @returns {Array} Array with all the headers of the specified name. - */ - getHeaders: function getHeaders(name) { - var idx, - length, - header = this.headers[SIP.Utils.headerize(name)], - result = []; - - if (!header) { - return []; - } - - length = header.length; - for (idx = 0; idx < length; idx++) { - result.push(header[idx].raw); - } - - return result; - }, - - /** - * Verify the existence of the given header. - * @param {String} name header name - * @returns {boolean} true if header with given name exists, false otherwise - */ - hasHeader: function hasHeader(name) { - return this.headers[SIP.Utils.headerize(name)] ? true : false; - }, - - /** - * Parse the given header on the given index. - * @param {String} name header name - * @param {Number} [idx=0] header index - * @returns {Object|undefined} Parsed header object, undefined if the header is not present or in case of a parsing error. - */ - parseHeader: function parseHeader(name, idx) { - var header, value, parsed; - - name = SIP.Utils.headerize(name); - - idx = idx || 0; - - if (!this.headers[name]) { - this.logger.log('header "' + name + '" not present'); - return; - } else if (idx >= this.headers[name].length) { - this.logger.log('not so many "' + name + '" headers present'); - return; - } - - header = this.headers[name][idx]; - value = header.raw; - - if (header.parsed) { - return header.parsed; - } - - //substitute '-' by '_' for grammar rule matching. - parsed = SIP.Grammar.parse(value, name.replace(/-/g, '_')); - - if (parsed === -1) { - this.headers[name].splice(idx, 1); //delete from headers - this.logger.warn('error parsing "' + name + '" header field with value "' + value + '"'); - return; - } else { - header.parsed = parsed; - return parsed; - } - }, - - /** - * Message Header attribute selector. Alias of parseHeader. - * @param {String} name header name - * @param {Number} [idx=0] header index - * @returns {Object|undefined} Parsed header object, undefined if the header is not present or in case of a parsing error. - * - * @example - * message.s('via',3).port - */ - s: function s(name, idx) { - return this.parseHeader(name, idx); - }, - - /** - * Replace the value of the given header by the value. - * @param {String} name header name - * @param {String} value header value - */ - setHeader: function setHeader(name, value) { - var header = { raw: value }; - this.headers[SIP.Utils.headerize(name)] = [header]; - }, - - toString: function toString() { - return this.data; - } - }; - - /** - * @augments IncomingMessage - * @class Class for incoming SIP request. - */ - IncomingRequest = function IncomingRequest(ua) { - this.logger = ua.getLogger('sip.sipmessage'); - this.ua = ua; - this.headers = {}; - this.ruri = null; - this.transport = null; - this.server_transaction = null; - }; - IncomingRequest.prototype = new IncomingMessage(); - - /** - * Stateful reply. - * @param {Number} code status code - * @param {String} reason reason phrase - * @param {Object} headers extra headers - * @param {String} body body - * @param {Function} [onSuccess] onSuccess callback - * @param {Function} [onFailure] onFailure callback - */ - // TODO: Get rid of callbacks and make promise based - IncomingRequest.prototype.reply = function (code, reason, extraHeaders, body, onSuccess, onFailure) { - var rr, - vias, - length, - idx, - response, - to = this.getHeader('To'), - r = 0, - v = 0; - - response = SIP.Utils.buildStatusLine(code, reason); - extraHeaders = (extraHeaders || []).slice(); - - if (this.method === SIP.C.INVITE && code > 100 && code <= 200) { - rr = this.getHeaders('record-route'); - length = rr.length; - - for (r; r < length; r++) { - response += 'Record-Route: ' + rr[r] + '\r\n'; - } - } - - vias = this.getHeaders('via'); - length = vias.length; - - for (v; v < length; v++) { - response += 'Via: ' + vias[v] + '\r\n'; - } - - if (!this.to_tag && code > 100) { - to += ';tag=' + SIP.Utils.newTag(); - } else if (this.to_tag && !this.s('to').hasParam('tag')) { - to += ';tag=' + this.to_tag; - } - - response += 'To: ' + to + '\r\n'; - response += 'From: ' + this.getHeader('From') + '\r\n'; - response += 'Call-ID: ' + this.call_id + '\r\n'; - response += 'CSeq: ' + this.cseq + ' ' + this.method + '\r\n'; - - length = extraHeaders.length; - for (idx = 0; idx < length; idx++) { - response += extraHeaders[idx].trim() + '\r\n'; - } - - response += getSupportedHeader(this); - response += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n'; - - if (body) { - if (typeof body === 'string') { - length = SIP.Utils.str_utf8_length(body); - response += 'Content-Type: application/sdp\r\n'; - response += 'Content-Length: ' + length + '\r\n\r\n'; - response += body; - } else { - if (body.body && body.contentType) { - length = SIP.Utils.str_utf8_length(body.body); - response += 'Content-Type: ' + body.contentType + '\r\n'; - response += 'Content-Length: ' + length + '\r\n\r\n'; - response += body.body; - } else { - response += 'Content-Length: ' + 0 + '\r\n\r\n'; - } - } - } else { - response += 'Content-Length: ' + 0 + '\r\n\r\n'; - } - - this.server_transaction.receiveResponse(code, response).then(onSuccess, onFailure); - - return response; - }; - - /** - * Stateless reply. - * @param {Number} code status code - * @param {String} reason reason phrase - */ - IncomingRequest.prototype.reply_sl = function (code, reason) { - var to, - response, - v = 0, - vias = this.getHeaders('via'), - length = vias.length; - - response = SIP.Utils.buildStatusLine(code, reason); - - for (v; v < length; v++) { - response += 'Via: ' + vias[v] + '\r\n'; - } - - to = this.getHeader('To'); - - if (!this.to_tag && code > 100) { - to += ';tag=' + SIP.Utils.newTag(); - } else if (this.to_tag && !this.s('to').hasParam('tag')) { - to += ';tag=' + this.to_tag; - } - - response += 'To: ' + to + '\r\n'; - response += 'From: ' + this.getHeader('From') + '\r\n'; - response += 'Call-ID: ' + this.call_id + '\r\n'; - response += 'CSeq: ' + this.cseq + ' ' + this.method + '\r\n'; - response += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n'; - response += 'Content-Length: ' + 0 + '\r\n\r\n'; - - this.transport.send(response); - }; - - /** - * @augments IncomingMessage - * @class Class for incoming SIP response. - */ - IncomingResponse = function IncomingResponse(ua) { - this.logger = ua.getLogger('sip.sipmessage'); - this.headers = {}; - this.status_code = null; - this.reason_phrase = null; - }; - IncomingResponse.prototype = new IncomingMessage(); - - SIP.OutgoingRequest = OutgoingRequest; - SIP.IncomingRequest = IncomingRequest; - SIP.IncomingResponse = IncomingResponse; -}; - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP URI - */ - -/** - * @augments SIP - * @class Class creating a SIP URI. - * - * @param {String} [scheme] - * @param {String} [user] - * @param {String} host - * @param {String} [port] - * @param {Object} [parameters] - * @param {Object} [headers] - * - */ - -module.exports = function (SIP) { - var URI; - - URI = function URI(scheme, user, host, port, parameters, headers) { - var param, header, raw, normal; - - // Checks - if (!host) { - throw new TypeError('missing or invalid "host" parameter'); - } - - // Initialize parameters - scheme = scheme || SIP.C.SIP; - this.parameters = {}; - this.headers = {}; - - for (param in parameters) { - this.setParam(param, parameters[param]); - } - - for (header in headers) { - this.setHeader(header, headers[header]); - } - - // Raw URI - raw = { - scheme: scheme, - user: user, - host: host, - port: port - }; - - // Normalized URI - normal = { - scheme: scheme.toLowerCase(), - user: user, - host: host.toLowerCase(), - port: port - }; - - Object.defineProperties(this, { - _normal: { - get: function get() { - return normal; - } - }, - - _raw: { - get: function get() { - return raw; - } - }, - - scheme: { - get: function get() { - return normal.scheme; - }, - set: function set(value) { - raw.scheme = value; - normal.scheme = value.toLowerCase(); - } - }, - - user: { - get: function get() { - return normal.user; - }, - set: function set(value) { - normal.user = raw.user = value; - } - }, - - host: { - get: function get() { - return normal.host; - }, - set: function set(value) { - raw.host = value; - normal.host = value.toLowerCase(); - } - }, - - aor: { - get: function get() { - return normal.user + '@' + normal.host; - } - }, - - port: { - get: function get() { - return normal.port; - }, - set: function set(value) { - normal.port = raw.port = value === 0 ? value : parseInt(value, 10) || null; - } - } - }); - }; - - URI.prototype = { - setParam: function setParam(key, value) { - if (key) { - this.parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString().toLowerCase(); - } - }, - - getParam: function getParam(key) { - if (key) { - return this.parameters[key.toLowerCase()]; - } - }, - - hasParam: function hasParam(key) { - if (key) { - return this.parameters.hasOwnProperty(key.toLowerCase()) && true || false; - } - }, - - deleteParam: function deleteParam(parameter) { - var value; - parameter = parameter.toLowerCase(); - if (this.parameters.hasOwnProperty(parameter)) { - value = this.parameters[parameter]; - delete this.parameters[parameter]; - return value; - } - }, - - clearParams: function clearParams() { - this.parameters = {}; - }, - - setHeader: function setHeader(name, value) { - this.headers[SIP.Utils.headerize(name)] = value instanceof Array ? value : [value]; - }, - - getHeader: function getHeader(name) { - if (name) { - return this.headers[SIP.Utils.headerize(name)]; - } - }, - - hasHeader: function hasHeader(name) { - if (name) { - return this.headers.hasOwnProperty(SIP.Utils.headerize(name)) && true || false; - } - }, - - deleteHeader: function deleteHeader(header) { - var value; - header = SIP.Utils.headerize(header); - if (this.headers.hasOwnProperty(header)) { - value = this.headers[header]; - delete this.headers[header]; - return value; - } - }, - - clearHeaders: function clearHeaders() { - this.headers = {}; - }, - - clone: function clone() { - return new URI(this._raw.scheme, this._raw.user, this._raw.host, this._raw.port, JSON.parse(JSON.stringify(this.parameters)), JSON.parse(JSON.stringify(this.headers))); - }, - - toRaw: function toRaw() { - return this._toString(this._raw); - }, - - toString: function toString() { - return this._toString(this._normal); - }, - - _toString: function _toString(uri) { - var header, - parameter, - idx, - uriString, - headers = []; - - uriString = uri.scheme + ':'; - // add slashes if it's not a sip(s) URI - if (!uri.scheme.toLowerCase().match("^sips?$")) { - uriString += "//"; - } - if (uri.user) { - uriString += SIP.Utils.escapeUser(uri.user) + '@'; - } - uriString += uri.host; - if (uri.port || uri.port === 0) { - uriString += ':' + uri.port; - } - - for (parameter in this.parameters) { - uriString += ';' + parameter; - - if (this.parameters[parameter] !== null) { - uriString += '=' + this.parameters[parameter]; - } - } - - for (header in this.headers) { - for (idx in this.headers[header]) { - headers.push(header + '=' + this.headers[header][idx]); - } - } - - if (headers.length > 0) { - uriString += '?' + headers.join('&'); - } - - return uriString; - } - }; - - /** - * Parse the given string and returns a SIP.URI instance or undefined if - * it is an invalid URI. - * @public - * @param {String} uri - */ - URI.parse = function (uri) { - uri = SIP.Grammar.parse(uri, 'SIP_URI'); - - if (uri !== -1) { - return uri; - } else { - return undefined; - } - }; - - SIP.URI = URI; -}; - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP NameAddrHeader - */ - -/** - * @augments SIP - * @class Class creating a Name Address SIP header. - * - * @param {SIP.URI} uri - * @param {String} [displayName] - * @param {Object} [parameters] - * - */ - -module.exports = function (SIP) { - var NameAddrHeader; - - NameAddrHeader = function NameAddrHeader(uri, displayName, parameters) { - var param; - - // Checks - if (!uri || !(uri instanceof SIP.URI)) { - throw new TypeError('missing or invalid "uri" parameter'); - } - - // Initialize parameters - this.uri = uri; - this.parameters = {}; - - for (param in parameters) { - this.setParam(param, parameters[param]); - } - - Object.defineProperties(this, { - friendlyName: { - get: function get() { - return this.displayName || uri.aor; - } - }, - - displayName: { - get: function get() { - return displayName; - }, - set: function set(value) { - displayName = value === 0 ? '0' : value; - } - } - }); - }; - NameAddrHeader.prototype = { - setParam: function setParam(key, value) { - if (key) { - this.parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString(); - } - }, - getParam: SIP.URI.prototype.getParam, - hasParam: SIP.URI.prototype.hasParam, - deleteParam: SIP.URI.prototype.deleteParam, - clearParams: SIP.URI.prototype.clearParams, - - clone: function clone() { - return new NameAddrHeader(this.uri.clone(), this.displayName, JSON.parse(JSON.stringify(this.parameters))); - }, - - toString: function toString() { - var body, parameter; - - body = this.displayName || this.displayName === 0 ? '"' + this.displayName + '" ' : ''; - body += '<' + this.uri.toString() + '>'; - - for (parameter in this.parameters) { - body += ';' + parameter; - - if (this.parameters[parameter] !== null) { - body += '=' + this.parameters[parameter]; - } - } - - return body; - } - }; - - /** - * Parse the given string and returns a SIP.NameAddrHeader instance or undefined if - * it is an invalid NameAddrHeader. - * @public - * @param {String} name_addr_header - */ - NameAddrHeader.parse = function (name_addr_header) { - name_addr_header = SIP.Grammar.parse(name_addr_header, 'Name_Addr_Header'); - - if (name_addr_header !== -1) { - return name_addr_header; - } else { - return undefined; - } - }; - - SIP.NameAddrHeader = NameAddrHeader; -}; - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Transactions - */ - -/** - * SIP Transactions module. - * @augments SIP - */ - -module.exports = function (SIP) { - var C = { - // Transaction states - STATUS_TRYING: 1, - STATUS_PROCEEDING: 2, - STATUS_CALLING: 3, - STATUS_ACCEPTED: 4, - STATUS_COMPLETED: 5, - STATUS_TERMINATED: 6, - STATUS_CONFIRMED: 7, - - // Transaction types - NON_INVITE_CLIENT: 'nict', - NON_INVITE_SERVER: 'nist', - INVITE_CLIENT: 'ict', - INVITE_SERVER: 'ist' - }; - - function buildViaHeader(request_sender, transport, id) { - var via; - via = 'SIP/2.0/' + (request_sender.ua.configuration.hackViaTcp ? 'TCP' : transport.server.scheme); - via += ' ' + request_sender.ua.configuration.viaHost + ';branch=' + id; - if (request_sender.ua.configuration.forceRport) { - via += ';rport'; - } - return via; - } - - /** - * @augments SIP.Transactions - * @class Non Invite Client Transaction - * @param {SIP.RequestSender} request_sender - * @param {SIP.OutgoingRequest} request - * @param {SIP.Transport} transport - */ - var NonInviteClientTransaction = function NonInviteClientTransaction(request_sender, request, transport) { - var via; - - this.type = C.NON_INVITE_CLIENT; - this.transport = transport; - this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000); - this.request_sender = request_sender; - this.request = request; - - this.logger = request_sender.ua.getLogger('sip.transaction.nict', this.id); - - via = buildViaHeader(request_sender, transport, this.id); - this.request.setHeader('via', via); - - this.request_sender.ua.newTransaction(this); - }; - NonInviteClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - NonInviteClientTransaction.prototype.stateChanged = function (state) { - this.state = state; - this.emit('stateChanged'); - }; - - NonInviteClientTransaction.prototype.send = function () { - var tr = this; - - this.stateChanged(C.STATUS_TRYING); - this.F = SIP.Timers.setTimeout(tr.timer_F.bind(tr), SIP.Timers.TIMER_F); - - if (!this.transport.send(this.request)) { - this.onTransportError(); - } - }; - - NonInviteClientTransaction.prototype.onTransportError = function () { - this.logger.log('transport error occurred, deleting non-INVITE client transaction ' + this.id); - SIP.Timers.clearTimeout(this.F); - SIP.Timers.clearTimeout(this.K); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - this.request_sender.onTransportError(); - }; - - NonInviteClientTransaction.prototype.timer_F = function () { - this.logger.debug('Timer F expired for non-INVITE client transaction ' + this.id); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - this.request_sender.onRequestTimeout(); - }; - - NonInviteClientTransaction.prototype.timer_K = function () { - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - }; - - NonInviteClientTransaction.prototype.receiveResponse = function (response) { - var tr = this, - status_code = response.status_code; - - if (status_code < 200) { - switch (this.state) { - case C.STATUS_TRYING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_PROCEEDING); - this.request_sender.receiveResponse(response); - break; - } - } else { - switch (this.state) { - case C.STATUS_TRYING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_COMPLETED); - SIP.Timers.clearTimeout(this.F); - - if (status_code === 408) { - this.request_sender.onRequestTimeout(); - } else { - this.request_sender.receiveResponse(response); - } - - this.K = SIP.Timers.setTimeout(tr.timer_K.bind(tr), SIP.Timers.TIMER_K); - break; - case C.STATUS_COMPLETED: - break; - } - } - }; - - /** - * @augments SIP.Transactions - * @class Invite Client Transaction - * @param {SIP.RequestSender} request_sender - * @param {SIP.OutgoingRequest} request - * @param {SIP.Transport} transport - */ - var InviteClientTransaction = function InviteClientTransaction(request_sender, request, transport) { - var via, - tr = this; - - this.type = C.INVITE_CLIENT; - this.transport = transport; - this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000); - this.request_sender = request_sender; - this.request = request; - - this.logger = request_sender.ua.getLogger('sip.transaction.ict', this.id); - - via = buildViaHeader(request_sender, transport, this.id); - this.request.setHeader('via', via); - - this.request_sender.ua.newTransaction(this); - - // Add the cancel property to the request. - //Will be called from the request instance, not the transaction itself. - this.request.cancel = function (reason, extraHeaders) { - extraHeaders = (extraHeaders || []).slice(); - var length = extraHeaders.length; - var extraHeadersString = null; - for (var idx = 0; idx < length; idx++) { - extraHeadersString = (extraHeadersString || '') + extraHeaders[idx].trim() + '\r\n'; - } - - tr.cancel_request(tr, reason, extraHeadersString); - }; - }; - InviteClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - InviteClientTransaction.prototype.stateChanged = function (state) { - this.state = state; - this.emit('stateChanged'); - }; - - InviteClientTransaction.prototype.send = function () { - var tr = this; - this.stateChanged(C.STATUS_CALLING); - this.B = SIP.Timers.setTimeout(tr.timer_B.bind(tr), SIP.Timers.TIMER_B); - - if (!this.transport.send(this.request)) { - this.onTransportError(); - } - }; - - InviteClientTransaction.prototype.onTransportError = function () { - this.logger.log('transport error occurred, deleting INVITE client transaction ' + this.id); - SIP.Timers.clearTimeout(this.B); - SIP.Timers.clearTimeout(this.D); - SIP.Timers.clearTimeout(this.M); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - - if (this.state !== C.STATUS_ACCEPTED) { - this.request_sender.onTransportError(); - } - }; - - // RFC 6026 7.2 - InviteClientTransaction.prototype.timer_M = function () { - this.logger.debug('Timer M expired for INVITE client transaction ' + this.id); - - if (this.state === C.STATUS_ACCEPTED) { - SIP.Timers.clearTimeout(this.B); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - } - }; - - // RFC 3261 17.1.1 - InviteClientTransaction.prototype.timer_B = function () { - this.logger.debug('Timer B expired for INVITE client transaction ' + this.id); - if (this.state === C.STATUS_CALLING) { - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - this.request_sender.onRequestTimeout(); - } - }; - - InviteClientTransaction.prototype.timer_D = function () { - this.logger.debug('Timer D expired for INVITE client transaction ' + this.id); - SIP.Timers.clearTimeout(this.B); - this.stateChanged(C.STATUS_TERMINATED); - this.request_sender.ua.destroyTransaction(this); - }; - - InviteClientTransaction.prototype.sendACK = function (options) { - // TODO: Move PRACK stuff into the transaction layer. That is really where it should be - - var self = this, - ruri; - options = options || {}; - - if (this.response.getHeader('contact')) { - ruri = this.response.parseHeader('contact').uri; - } else { - ruri = this.request.ruri; - } - var ack = new SIP.OutgoingRequest("ACK", ruri, this.request.ua, { - cseq: this.response.cseq, - call_id: this.response.call_id, - from_uri: this.response.from.uri, - from_tag: this.response.from_tag, - to_uri: this.response.to.uri, - to_tag: this.response.to_tag, - route_set: this.response.getHeaders('record-route').reverse() - }, options.extraHeaders || [], options.body); - - this.ackSender = new SIP.RequestSender({ - request: ack, - onRequestTimeout: this.request_sender.applicant.applicant ? this.request_sender.applicant.applicant.onRequestTimeout : function () { - self.logger.warn("ACK Request timed out"); - }, - onTransportError: this.request_sender.applicant.applicant ? this.request_sender.applicant.applicant.onRequestTransportError : function () { - self.loigger.warn("ACK Request had a transport error"); - }, - receiveResponse: options.receiveResponse || function () { - self.logger.warn("Received a response to an ACK which was unexpected. Dropping Response."); - } - }, this.request.ua).send(); - - return ack; - }; - - InviteClientTransaction.prototype.cancel_request = function (tr, reason, extraHeaders) { - var request = tr.request; - - this.cancel = SIP.C.CANCEL + ' ' + request.ruri + ' SIP/2.0\r\n'; - this.cancel += 'Via: ' + request.headers['Via'].toString() + '\r\n'; - - if (this.request.headers['Route']) { - this.cancel += 'Route: ' + request.headers['Route'].toString() + '\r\n'; - } - - this.cancel += 'To: ' + request.headers['To'].toString() + '\r\n'; - this.cancel += 'From: ' + request.headers['From'].toString() + '\r\n'; - this.cancel += 'Call-ID: ' + request.headers['Call-ID'].toString() + '\r\n'; - this.cancel += 'CSeq: ' + request.headers['CSeq'].toString().split(' ')[0] + ' CANCEL\r\n'; - - if (reason) { - this.cancel += 'Reason: ' + reason + '\r\n'; - } - - if (extraHeaders) { - this.cancel += extraHeaders; - } - - this.cancel += 'Content-Length: 0\r\n\r\n'; - - // Send only if a provisional response (>100) has been received. - if (this.state === C.STATUS_PROCEEDING) { - this.transport.send(this.cancel); - } - }; - - InviteClientTransaction.prototype.receiveResponse = function (response) { - var tr = this, - status_code = response.status_code; - - // This may create a circular dependency... - response.transaction = this; - - if (this.response && this.response.status_code === response.status_code && this.response.cseq === response.cseq) { - this.logger.debug("ICT Received a retransmission for cseq: " + response.cseq); - if (this.ackSender) { - this.ackSender.send(); - } - return; - } - this.response = response; - - if (status_code >= 100 && status_code <= 199) { - switch (this.state) { - case C.STATUS_CALLING: - this.stateChanged(C.STATUS_PROCEEDING); - this.request_sender.receiveResponse(response); - if (this.cancel) { - this.transport.send(this.cancel); - } - break; - case C.STATUS_PROCEEDING: - this.request_sender.receiveResponse(response); - break; - } - } else if (status_code >= 200 && status_code <= 299) { - switch (this.state) { - case C.STATUS_CALLING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_ACCEPTED); - this.M = SIP.Timers.setTimeout(tr.timer_M.bind(tr), SIP.Timers.TIMER_M); - this.request_sender.receiveResponse(response); - break; - case C.STATUS_ACCEPTED: - this.request_sender.receiveResponse(response); - break; - } - } else if (status_code >= 300 && status_code <= 699) { - switch (this.state) { - case C.STATUS_CALLING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_COMPLETED); - this.sendACK(); - this.request_sender.receiveResponse(response); - break; - case C.STATUS_COMPLETED: - this.sendACK(); - break; - } - } - }; - - /** - * @augments SIP.Transactions - * @class ACK Client Transaction - * @param {SIP.RequestSender} request_sender - * @param {SIP.OutgoingRequest} request - * @param {SIP.Transport} transport - */ - var AckClientTransaction = function AckClientTransaction(request_sender, request, transport) { - var via; - - this.transport = transport; - this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000); - this.request_sender = request_sender; - this.request = request; - - this.logger = request_sender.ua.getLogger('sip.transaction.nict', this.id); - - via = buildViaHeader(request_sender, transport, this.id); - this.request.setHeader('via', via); - }; - AckClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - AckClientTransaction.prototype.send = function () { - if (!this.transport.send(this.request)) { - this.onTransportError(); - } - }; - - AckClientTransaction.prototype.onTransportError = function () { - this.logger.log('transport error occurred, for an ACK client transaction ' + this.id); - this.request_sender.onTransportError(); - }; - - /** - * @augments SIP.Transactions - * @class Non Invite Server Transaction - * @param {SIP.IncomingRequest} request - * @param {SIP.UA} ua - */ - var NonInviteServerTransaction = function NonInviteServerTransaction(request, ua) { - this.type = C.NON_INVITE_SERVER; - this.id = request.via_branch; - this.request = request; - this.transport = request.transport; - this.ua = ua; - this.last_response = ''; - request.server_transaction = this; - - this.logger = ua.getLogger('sip.transaction.nist', this.id); - - this.state = C.STATUS_TRYING; - - ua.newTransaction(this); - }; - NonInviteServerTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - NonInviteServerTransaction.prototype.stateChanged = function (state) { - this.state = state; - this.emit('stateChanged'); - }; - - NonInviteServerTransaction.prototype.timer_J = function () { - this.logger.debug('Timer J expired for non-INVITE server transaction ' + this.id); - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - }; - - NonInviteServerTransaction.prototype.onTransportError = function () { - if (!this.transportError) { - this.transportError = true; - - this.logger.log('transport error occurred, deleting non-INVITE server transaction ' + this.id); - - SIP.Timers.clearTimeout(this.J); - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - } - }; - - NonInviteServerTransaction.prototype.receiveResponse = function (status_code, response) { - var tr = this; - var deferred = SIP.Utils.defer(); - - if (status_code === 100) { - /* RFC 4320 4.1 - * 'A SIP element MUST NOT - * send any provisional response with a - * Status-Code other than 100 to a non-INVITE request.' - */ - switch (this.state) { - case C.STATUS_TRYING: - this.stateChanged(C.STATUS_PROCEEDING); - if (!this.transport.send(response)) { - this.onTransportError(); - } - break; - case C.STATUS_PROCEEDING: - this.last_response = response; - if (!this.transport.send(response)) { - this.onTransportError(); - deferred.reject(); - } else { - deferred.resolve(); - } - break; - } - } else if (status_code >= 200 && status_code <= 699) { - switch (this.state) { - case C.STATUS_TRYING: - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_COMPLETED); - this.last_response = response; - this.J = SIP.Timers.setTimeout(tr.timer_J.bind(tr), SIP.Timers.TIMER_J); - if (!this.transport.send(response)) { - this.onTransportError(); - deferred.reject(); - } else { - deferred.resolve(); - } - break; - case C.STATUS_COMPLETED: - break; - } - } - - return deferred.promise; - }; - - /** - * @augments SIP.Transactions - * @class Invite Server Transaction - * @param {SIP.IncomingRequest} request - * @param {SIP.UA} ua - */ - var InviteServerTransaction = function InviteServerTransaction(request, ua) { - this.type = C.INVITE_SERVER; - this.id = request.via_branch; - this.request = request; - this.transport = request.transport; - this.ua = ua; - this.last_response = ''; - request.server_transaction = this; - - this.logger = ua.getLogger('sip.transaction.ist', this.id); - - this.state = C.STATUS_PROCEEDING; - - ua.newTransaction(this); - - this.resendProvisionalTimer = null; - - request.reply(100); - }; - InviteServerTransaction.prototype = Object.create(SIP.EventEmitter.prototype); - - InviteServerTransaction.prototype.stateChanged = function (state) { - this.state = state; - this.emit('stateChanged'); - }; - - InviteServerTransaction.prototype.timer_H = function () { - this.logger.debug('Timer H expired for INVITE server transaction ' + this.id); - - if (this.state === C.STATUS_COMPLETED) { - this.logger.warn('transactions', 'ACK for INVITE server transaction was never received, call will be terminated'); - } - - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - }; - - InviteServerTransaction.prototype.timer_I = function () { - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - }; - - // RFC 6026 7.1 - InviteServerTransaction.prototype.timer_L = function () { - this.logger.debug('Timer L expired for INVITE server transaction ' + this.id); - - if (this.state === C.STATUS_ACCEPTED) { - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - } - }; - - InviteServerTransaction.prototype.onTransportError = function () { - if (!this.transportError) { - this.transportError = true; - - this.logger.log('transport error occurred, deleting INVITE server transaction ' + this.id); - - if (this.resendProvisionalTimer !== null) { - SIP.Timers.clearInterval(this.resendProvisionalTimer); - this.resendProvisionalTimer = null; - } - - SIP.Timers.clearTimeout(this.L); - SIP.Timers.clearTimeout(this.H); - SIP.Timers.clearTimeout(this.I); - - this.stateChanged(C.STATUS_TERMINATED); - this.ua.destroyTransaction(this); - } - }; - - InviteServerTransaction.prototype.resend_provisional = function () { - if (!this.transport.send(this.last_response)) { - this.onTransportError(); - } - }; - - // INVITE Server Transaction RFC 3261 17.2.1 - InviteServerTransaction.prototype.receiveResponse = function (status_code, response) { - var tr = this; - var deferred = SIP.Utils.defer(); - - if (status_code >= 100 && status_code <= 199) { - switch (this.state) { - case C.STATUS_PROCEEDING: - if (!this.transport.send(response)) { - this.onTransportError(); - } - this.last_response = response; - break; - } - } - - if (status_code > 100 && status_code <= 199 && this.state === C.STATUS_PROCEEDING) { - // Trigger the resendProvisionalTimer only for the first non 100 provisional response. - if (this.resendProvisionalTimer === null) { - this.resendProvisionalTimer = SIP.Timers.setInterval(tr.resend_provisional.bind(tr), SIP.Timers.PROVISIONAL_RESPONSE_INTERVAL); - } - } else if (status_code >= 200 && status_code <= 299) { - switch (this.state) { - case C.STATUS_PROCEEDING: - this.stateChanged(C.STATUS_ACCEPTED); - this.last_response = response; - this.L = SIP.Timers.setTimeout(tr.timer_L.bind(tr), SIP.Timers.TIMER_L); - - if (this.resendProvisionalTimer !== null) { - SIP.Timers.clearInterval(this.resendProvisionalTimer); - this.resendProvisionalTimer = null; - } - /* falls through */ - case C.STATUS_ACCEPTED: - // Note that this point will be reached for proceeding tr.state also. - if (!this.transport.send(response)) { - this.onTransportError(); - deferred.reject(); - } else { - deferred.resolve(); - } - break; - } - } else if (status_code >= 300 && status_code <= 699) { - switch (this.state) { - case C.STATUS_PROCEEDING: - if (this.resendProvisionalTimer !== null) { - SIP.Timers.clearInterval(this.resendProvisionalTimer); - this.resendProvisionalTimer = null; - } - - if (!this.transport.send(response)) { - this.onTransportError(); - deferred.reject(); - } else { - this.stateChanged(C.STATUS_COMPLETED); - this.H = SIP.Timers.setTimeout(tr.timer_H.bind(tr), SIP.Timers.TIMER_H); - deferred.resolve(); - } - break; - } - } - - return deferred.promise; - }; - - /** - * @function - * @param {SIP.UA} ua - * @param {SIP.IncomingRequest} request - * - * @return {boolean} - * INVITE: - * _true_ if retransmission - * _false_ new request - * - * ACK: - * _true_ ACK to non2xx response - * _false_ ACK must be passed to TU (accepted state) - * ACK to 2xx response - * - * CANCEL: - * _true_ no matching invite transaction - * _false_ matching invite transaction and no final response sent - * - * OTHER: - * _true_ retransmission - * _false_ new request - */ - var checkTransaction = function checkTransaction(ua, request) { - var tr; - - switch (request.method) { - case SIP.C.INVITE: - tr = ua.transactions.ist[request.via_branch]; - if (tr) { - switch (tr.state) { - case C.STATUS_PROCEEDING: - tr.transport.send(tr.last_response); - break; - - // RFC 6026 7.1 Invite retransmission - //received while in C.STATUS_ACCEPTED state. Absorb it. - case C.STATUS_ACCEPTED: - break; - } - return true; - } - break; - case SIP.C.ACK: - tr = ua.transactions.ist[request.via_branch]; - - // RFC 6026 7.1 - if (tr) { - if (tr.state === C.STATUS_ACCEPTED) { - return false; - } else if (tr.state === C.STATUS_COMPLETED) { - tr.stateChanged(C.STATUS_CONFIRMED); - tr.I = SIP.Timers.setTimeout(tr.timer_I.bind(tr), SIP.Timers.TIMER_I); - return true; - } - } - - // ACK to 2XX Response. - else { - return false; - } - break; - case SIP.C.CANCEL: - tr = ua.transactions.ist[request.via_branch]; - if (tr) { - request.reply_sl(200); - if (tr.state === C.STATUS_PROCEEDING) { - return false; - } else { - return true; - } - } else { - request.reply_sl(481); - return true; - } - default: - - // Non-INVITE Server Transaction RFC 3261 17.2.2 - tr = ua.transactions.nist[request.via_branch]; - if (tr) { - switch (tr.state) { - case C.STATUS_TRYING: - break; - case C.STATUS_PROCEEDING: - case C.STATUS_COMPLETED: - tr.transport.send(tr.last_response); - break; - } - return true; - } - break; - } - }; - - SIP.Transactions = { - C: C, - checkTransaction: checkTransaction, - NonInviteClientTransaction: NonInviteClientTransaction, - InviteClientTransaction: InviteClientTransaction, - AckClientTransaction: AckClientTransaction, - NonInviteServerTransaction: NonInviteServerTransaction, - InviteServerTransaction: InviteServerTransaction - }; -}; - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview SIP Dialog - */ - -/** - * @augments SIP - * @class Class creating a SIP dialog. - * @param {SIP.RTCSession} owner - * @param {SIP.IncomingRequest|SIP.IncomingResponse} message - * @param {Enum} type UAC / UAS - * @param {Enum} state SIP.Dialog.C.STATUS_EARLY / SIP.Dialog.C.STATUS_CONFIRMED - */ - -module.exports = function (SIP) { - - var RequestSender = __webpack_require__(17)(SIP); - - var Dialog, - C = { - // Dialog states - STATUS_EARLY: 1, - STATUS_CONFIRMED: 2 - }; - - // RFC 3261 12.1 - Dialog = function Dialog(owner, message, type, state) { - var contact; - - this.uac_pending_reply = false; - this.uas_pending_reply = false; - - if (!message.hasHeader('contact')) { - return { - error: 'unable to create a Dialog without Contact header field' - }; - } - - if (message instanceof SIP.IncomingResponse) { - state = message.status_code < 200 ? C.STATUS_EARLY : C.STATUS_CONFIRMED; - } else { - // Create confirmed dialog if state is not defined - state = state || C.STATUS_CONFIRMED; - } - - contact = message.parseHeader('contact'); - - // RFC 3261 12.1.1 - if (type === 'UAS') { - this.id = { - call_id: message.call_id, - local_tag: message.to_tag, - remote_tag: message.from_tag, - toString: function toString() { - return this.call_id + this.local_tag + this.remote_tag; - } - }; - this.state = state; - this.remote_seqnum = message.cseq; - this.local_uri = message.parseHeader('to').uri; - this.remote_uri = message.parseHeader('from').uri; - this.remote_target = contact.uri; - this.route_set = message.getHeaders('record-route'); - this.invite_seqnum = message.cseq; - this.local_seqnum = message.cseq; - } - // RFC 3261 12.1.2 - else if (type === 'UAC') { - this.id = { - call_id: message.call_id, - local_tag: message.from_tag, - remote_tag: message.to_tag, - toString: function toString() { - return this.call_id + this.local_tag + this.remote_tag; - } - }; - this.state = state; - this.invite_seqnum = message.cseq; - this.local_seqnum = message.cseq; - this.local_uri = message.parseHeader('from').uri; - this.pracked = []; - this.remote_uri = message.parseHeader('to').uri; - this.remote_target = contact.uri; - this.route_set = message.getHeaders('record-route').reverse(); - } - - this.logger = owner.ua.getLogger('sip.dialog', this.id.toString()); - this.owner = owner; - owner.ua.dialogs[this.id.toString()] = this; - this.logger.log('new ' + type + ' dialog created with status ' + (this.state === C.STATUS_EARLY ? 'EARLY' : 'CONFIRMED')); - owner.emit('dialog', this); - }; - - Dialog.prototype = { - /** - * @param {SIP.IncomingMessage} message - * @param {Enum} UAC/UAS - */ - update: function update(message, type) { - this.state = C.STATUS_CONFIRMED; - - this.logger.log('dialog ' + this.id.toString() + ' changed to CONFIRMED state'); - - if (type === 'UAC') { - // RFC 3261 13.2.2.4 - this.route_set = message.getHeaders('record-route').reverse(); - } - }, - - terminate: function terminate() { - this.logger.log('dialog ' + this.id.toString() + ' deleted'); - if (this.sessionDescriptionHandler && this.state !== C.STATUS_CONFIRMED) { - // TODO: This should call .close() on the handler when implemented - this.sessionDescriptionHandler.close(); - } - delete this.owner.ua.dialogs[this.id.toString()]; - }, - - /** - * @param {String} method request method - * @param {Object} extraHeaders extra headers - * @returns {SIP.OutgoingRequest} - */ - - // RFC 3261 12.2.1.1 - createRequest: function createRequest(method, extraHeaders, body) { - var cseq, request; - extraHeaders = (extraHeaders || []).slice(); - - if (!this.local_seqnum) { - this.local_seqnum = Math.floor(Math.random() * 10000); - } - - cseq = method === SIP.C.CANCEL || method === SIP.C.ACK ? this.invite_seqnum : this.local_seqnum += 1; - - request = new SIP.OutgoingRequest(method, this.remote_target, this.owner.ua, { - 'cseq': cseq, - 'call_id': this.id.call_id, - 'from_uri': this.local_uri, - 'from_tag': this.id.local_tag, - 'to_uri': this.remote_uri, - 'to_tag': this.id.remote_tag, - 'route_set': this.route_set - }, extraHeaders, body); - - request.dialog = this; - - return request; - }, - - /** - * @param {SIP.IncomingRequest} request - * @returns {Boolean} - */ - - // RFC 3261 12.2.2 - checkInDialogRequest: function checkInDialogRequest(request) { - var self = this; - - if (!this.remote_seqnum) { - this.remote_seqnum = request.cseq; - } else if (request.cseq < this.remote_seqnum) { - //Do not try to reply to an ACK request. - if (request.method !== SIP.C.ACK) { - request.reply(500); - } - if (request.cseq === this.invite_seqnum) { - return true; - } - return false; - } - - switch (request.method) { - // RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR- - case SIP.C.INVITE: - if (this.uac_pending_reply === true) { - request.reply(491); - } else if (this.uas_pending_reply === true && request.cseq > this.remote_seqnum) { - var retryAfter = (Math.random() * 10 | 0) + 1; - request.reply(500, null, ['Retry-After:' + retryAfter]); - this.remote_seqnum = request.cseq; - return false; - } else { - this.uas_pending_reply = true; - request.server_transaction.on('stateChanged', function stateChanged() { - if (this.state === SIP.Transactions.C.STATUS_ACCEPTED || this.state === SIP.Transactions.C.STATUS_COMPLETED || this.state === SIP.Transactions.C.STATUS_TERMINATED) { - - this.removeListener('stateChanged', stateChanged); - self.uas_pending_reply = false; - } - }); - } - - // RFC3261 12.2.2 Replace the dialog`s remote target URI if the request is accepted - if (request.hasHeader('contact')) { - request.server_transaction.on('stateChanged', function () { - if (this.state === SIP.Transactions.C.STATUS_ACCEPTED) { - self.remote_target = request.parseHeader('contact').uri; - } - }); - } - break; - case SIP.C.NOTIFY: - // RFC6665 3.2 Replace the dialog`s remote target URI if the request is accepted - if (request.hasHeader('contact')) { - request.server_transaction.on('stateChanged', function () { - if (this.state === SIP.Transactions.C.STATUS_COMPLETED) { - self.remote_target = request.parseHeader('contact').uri; - } - }); - } - break; - } - - if (request.cseq > this.remote_seqnum) { - this.remote_seqnum = request.cseq; - } - - return true; - }, - - sendRequest: function sendRequest(applicant, method, options) { - options = options || {}; - - var extraHeaders = (options.extraHeaders || []).slice(); - - var body = null; - if (options.body) { - if (options.body.body) { - body = options.body; - } else { - body = {}; - body.body = options.body; - if (options.contentType) { - body.contentType = options.contentType; - } - } - } - - var request = this.createRequest(method, extraHeaders, body), - request_sender = new RequestSender(this, applicant, request); - - request_sender.send(); - - return request; - }, - - /** - * @param {SIP.IncomingRequest} request - */ - receiveRequest: function receiveRequest(request) { - //Check in-dialog request - if (!this.checkInDialogRequest(request)) { - return; - } - - this.owner.receiveRequest(request); - } - }; - - Dialog.C = C; - SIP.Dialog = Dialog; -}; - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * @fileoverview In-Dialog Request Sender - */ - -/** - * @augments SIP.Dialog - * @class Class creating an In-dialog request sender. - * @param {SIP.Dialog} dialog - * @param {Object} applicant - * @param {SIP.OutgoingRequest} request - */ -/** - * @fileoverview in-Dialog Request Sender - */ - -module.exports = function (SIP) { - var RequestSender; - - RequestSender = function RequestSender(dialog, applicant, request) { - - this.dialog = dialog; - this.applicant = applicant; - this.request = request; - - // RFC3261 14.1 Modifying an Existing Session. UAC Behavior. - this.reattempt = false; - this.reattemptTimer = null; - }; - - RequestSender.prototype = { - send: function send() { - var self = this, - request_sender = new SIP.RequestSender(this, this.dialog.owner.ua); - - request_sender.send(); - - // RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR- - if (this.request.method === SIP.C.INVITE && request_sender.clientTransaction.state !== SIP.Transactions.C.STATUS_TERMINATED) { - this.dialog.uac_pending_reply = true; - request_sender.clientTransaction.on('stateChanged', function stateChanged() { - if (this.state === SIP.Transactions.C.STATUS_ACCEPTED || this.state === SIP.Transactions.C.STATUS_COMPLETED || this.state === SIP.Transactions.C.STATUS_TERMINATED) { - - this.removeListener('stateChanged', stateChanged); - self.dialog.uac_pending_reply = false; - } - }); - } - }, - - onRequestTimeout: function onRequestTimeout() { - this.applicant.onRequestTimeout(); - }, - - onTransportError: function onTransportError() { - this.applicant.onTransportError(); - }, - - receiveResponse: function receiveResponse(response) { - var self = this; - - // RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog. - if (response.status_code === 408 || response.status_code === 481) { - this.applicant.onDialogError(response); - } else if (response.method === SIP.C.INVITE && response.status_code === 491) { - if (this.reattempt) { - this.applicant.receiveResponse(response); - } else { - this.request.cseq.value = this.dialog.local_seqnum += 1; - this.reattemptTimer = SIP.Timers.setTimeout(function () { - if (self.applicant.owner.status !== SIP.Session.C.STATUS_TERMINATED) { - self.reattempt = true; - self.request_sender.send(); - } - }, this.getReattemptTimeout()); - } - } else { - this.applicant.receiveResponse(response); - } - } - }; - - return RequestSender; -}; - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * @fileoverview Request Sender - */ - -/** - * @augments SIP - * @class Class creating a request sender. - * @param {Object} applicant - * @param {SIP.UA} ua - */ - -module.exports = function (SIP) { - var RequestSender; - - RequestSender = function RequestSender(applicant, ua) { - this.logger = ua.getLogger('sip.requestsender'); - this.ua = ua; - this.applicant = applicant; - this.method = applicant.request.method; - this.request = applicant.request; - this.credentials = null; - this.challenged = false; - this.staled = false; - - // If ua is in closing process or even closed just allow sending Bye and ACK - if (ua.status === SIP.UA.C.STATUS_USER_CLOSED && (this.method !== SIP.C.BYE || this.method !== SIP.C.ACK)) { - this.onTransportError(); - } - }; - - /** - * Create the client transaction and send the message. - */ - RequestSender.prototype = { - send: function send() { - switch (this.method) { - case "INVITE": - this.clientTransaction = new SIP.Transactions.InviteClientTransaction(this, this.request, this.ua.transport); - break; - case "ACK": - this.clientTransaction = new SIP.Transactions.AckClientTransaction(this, this.request, this.ua.transport); - break; - default: - this.clientTransaction = new SIP.Transactions.NonInviteClientTransaction(this, this.request, this.ua.transport); - } - this.clientTransaction.send(); - - return this.clientTransaction; - }, - - /** - * Callback fired when receiving a request timeout error from the client transaction. - * To be re-defined by the applicant. - * @event - */ - onRequestTimeout: function onRequestTimeout() { - this.applicant.onRequestTimeout(); - }, - - /** - * Callback fired when receiving a transport error from the client transaction. - * To be re-defined by the applicant. - * @event - */ - onTransportError: function onTransportError() { - this.applicant.onTransportError(); - }, - - /** - * Called from client transaction when receiving a correct response to the request. - * Authenticate request if needed or pass the response back to the applicant. - * @param {SIP.IncomingResponse} response - */ - receiveResponse: function receiveResponse(response) { - var cseq, - challenge, - authorization_header_name, - status_code = response.status_code; - - /* - * Authentication - * Authenticate once. _challenged_ flag used to avoid infinite authentications. - */ - if (status_code === 401 || status_code === 407) { - - // Get and parse the appropriate WWW-Authenticate or Proxy-Authenticate header. - if (response.status_code === 401) { - challenge = response.parseHeader('www-authenticate'); - authorization_header_name = 'authorization'; - } else { - challenge = response.parseHeader('proxy-authenticate'); - authorization_header_name = 'proxy-authorization'; - } - - // Verify it seems a valid challenge. - if (!challenge) { - this.logger.warn(response.status_code + ' with wrong or missing challenge, cannot authenticate'); - this.applicant.receiveResponse(response); - return; - } - - if (!this.challenged || !this.staled && challenge.stale === true) { - if (!this.credentials) { - this.credentials = this.ua.configuration.authenticationFactory(this.ua); - } - - // Verify that the challenge is really valid. - if (!this.credentials.authenticate(this.request, challenge)) { - this.applicant.receiveResponse(response); - return; - } - this.challenged = true; - - if (challenge.stale) { - this.staled = true; - } - - if (response.method === SIP.C.REGISTER) { - cseq = this.applicant.cseq += 1; - } else if (this.request.dialog) { - cseq = this.request.dialog.local_seqnum += 1; - } else { - cseq = this.request.cseq + 1; - this.request.cseq = cseq; - } - this.request.setHeader('cseq', cseq + ' ' + this.method); - - this.request.setHeader(authorization_header_name, this.credentials.toString()); - this.send(); - } else { - this.applicant.receiveResponse(response); - } - } else { - this.applicant.receiveResponse(response); - } - } - }; - - SIP.RequestSender = RequestSender; -}; - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function (SIP) { - - var RegisterContext; - - RegisterContext = function RegisterContext(ua) { - var params = {}, - regId = 1; - - this.registrar = ua.configuration.registrarServer; - this.expires = ua.configuration.registerExpires; - - // Contact header - this.contact = ua.contact.toString(); - - if (regId) { - this.contact += ';reg-id=' + regId; - this.contact += ';+sip.instance=""'; - } - - // Call-ID and CSeq values RFC3261 10.2 - this.call_id = SIP.Utils.createRandomToken(22); - this.cseq = Math.floor(Math.random() * 10000); - - this.to_uri = ua.configuration.uri; - - params.to_uri = this.to_uri; - params.to_displayName = ua.configuration.displayName; - params.call_id = this.call_id; - params.cseq = this.cseq; - - // Extends ClientContext - SIP.Utils.augment(this, SIP.ClientContext, [ua, 'REGISTER', this.registrar, { params: params }]); - - this.registrationTimer = null; - this.registrationExpiredTimer = null; - - // Set status - this.registered = false; - - this.logger = ua.getLogger('sip.registercontext'); - }; - - RegisterContext.prototype = { - register: function register(options) { - var self = this, - extraHeaders; - - // Handle Options - this.options = options || {}; - extraHeaders = (this.options.extraHeaders || []).slice(); - extraHeaders.push('Contact: ' + this.contact + ';expires=' + this.expires); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - // Save original extraHeaders to be used in .close - this.closeHeaders = this.options.closeWithHeaders ? (this.options.extraHeaders || []).slice() : []; - - this.receiveResponse = function (response) { - var contact, - expires, - contacts = response.getHeaders('contact').length, - cause; - - // Discard responses to older REGISTER/un-REGISTER requests. - if (response.cseq !== this.cseq) { - return; - } - - // Clear registration timer - if (this.registrationTimer !== null) { - SIP.Timers.clearTimeout(this.registrationTimer); - this.registrationTimer = null; - } - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - this.emit('progress', response); - break; - case /^2[0-9]{2}$/.test(response.status_code): - this.emit('accepted', response); - - if (response.hasHeader('expires')) { - expires = response.getHeader('expires'); - } - - if (this.registrationExpiredTimer !== null) { - SIP.Timers.clearTimeout(this.registrationExpiredTimer); - this.registrationExpiredTimer = null; - } - - // Search the Contact pointing to us and update the expires value accordingly. - if (!contacts) { - this.logger.warn('no Contact header in response to REGISTER, response ignored'); - break; - } - - while (contacts--) { - contact = response.parseHeader('contact', contacts); - if (contact.uri.user === this.ua.contact.uri.user) { - expires = contact.getParam('expires'); - break; - } else { - contact = null; - } - } - - if (!contact) { - this.logger.warn('no Contact header pointing to us, response ignored'); - break; - } - - if (!expires) { - expires = this.expires; - } - - // Re-Register before the expiration interval has elapsed. - // For that, decrease the expires value. ie: 3 seconds - this.registrationTimer = SIP.Timers.setTimeout(function () { - self.registrationTimer = null; - self.register(self.options); - }, expires * 1000 - 3000); - this.registrationExpiredTimer = SIP.Timers.setTimeout(function () { - self.logger.warn('registration expired'); - if (self.registered) { - self.unregistered(null, SIP.C.causes.EXPIRES); - } - }, expires * 1000); - - //Save gruu values - if (contact.hasParam('temp-gruu')) { - this.ua.contact.temp_gruu = SIP.URI.parse(contact.getParam('temp-gruu').replace(/"/g, '')); - } - if (contact.hasParam('pub-gruu')) { - this.ua.contact.pub_gruu = SIP.URI.parse(contact.getParam('pub-gruu').replace(/"/g, '')); - } - - this.registered = true; - this.emit('registered', response || null); - break; - // Interval too brief RFC3261 10.2.8 - case /^423$/.test(response.status_code): - if (response.hasHeader('min-expires')) { - // Increase our registration interval to the suggested minimum - this.expires = response.getHeader('min-expires'); - // Attempt the registration again immediately - this.register(this.options); - } else { - //This response MUST contain a Min-Expires header field - this.logger.warn('423 response received for REGISTER without Min-Expires'); - this.registrationFailure(response, SIP.C.causes.SIP_FAILURE_CODE); - } - break; - default: - cause = SIP.Utils.sipErrorCause(response.status_code); - this.registrationFailure(response, cause); - } - }; - - this.onRequestTimeout = function () { - this.registrationFailure(null, SIP.C.causes.REQUEST_TIMEOUT); - }; - - this.onTransportError = function () { - this.registrationFailure(null, SIP.C.causes.CONNECTION_ERROR); - }; - - this.cseq++; - this.request.cseq = this.cseq; - this.request.setHeader('cseq', this.cseq + ' REGISTER'); - this.request.extraHeaders = extraHeaders; - this.send(); - }, - - registrationFailure: function registrationFailure(response, cause) { - this.emit('failed', response || null, cause || null); - }, - - onTransportClosed: function onTransportClosed() { - this.registered_before = this.registered; - if (this.registrationTimer !== null) { - SIP.Timers.clearTimeout(this.registrationTimer); - this.registrationTimer = null; - } - - if (this.registrationExpiredTimer !== null) { - SIP.Timers.clearTimeout(this.registrationExpiredTimer); - this.registrationExpiredTimer = null; - } - - if (this.registered) { - this.unregistered(null, SIP.C.causes.CONNECTION_ERROR); - } - }, - - onTransportConnected: function onTransportConnected() { - this.register(this.options); - }, - - close: function close() { - var options = { - all: false, - extraHeaders: this.closeHeaders - }; - - this.registered_before = this.registered; - if (this.registered) { - this.unregister(options); - } - }, - - unregister: function unregister(options) { - var extraHeaders; - - options = options || {}; - - if (!this.registered && !options.all) { - this.logger.warn('Already unregistered, but sending an unregister anyways.'); - } - - extraHeaders = (options.extraHeaders || []).slice(); - - this.registered = false; - - // Clear the registration timer. - if (this.registrationTimer !== null) { - SIP.Timers.clearTimeout(this.registrationTimer); - this.registrationTimer = null; - } - - if (options.all) { - extraHeaders.push('Contact: *'); - extraHeaders.push('Expires: 0'); - } else { - extraHeaders.push('Contact: ' + this.contact + ';expires=0'); - } - - this.receiveResponse = function (response) { - var cause; - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - this.emit('progress', response); - break; - case /^2[0-9]{2}$/.test(response.status_code): - this.emit('accepted', response); - if (this.registrationExpiredTimer !== null) { - SIP.Timers.clearTimeout(this.registrationExpiredTimer); - this.registrationExpiredTimer = null; - } - this.unregistered(response); - break; - default: - cause = SIP.Utils.sipErrorCause(response.status_code); - this.unregistered(response, cause); - } - }; - - this.onRequestTimeout = function () { - // Not actually unregistered... - //this.unregistered(null, SIP.C.causes.REQUEST_TIMEOUT); - }; - - this.onTransportError = function () { - // Not actually unregistered... - //this.unregistered(null, SIP.C.causes.CONNECTION_ERROR); - }; - - this.cseq++; - this.request.cseq = this.cseq; - this.request.setHeader('cseq', this.cseq + ' REGISTER'); - this.request.extraHeaders = extraHeaders; - - this.send(); - }, - - unregistered: function unregistered(response, cause) { - this.registered = false; - this.emit('unregistered', response || null, cause || null); - } - - }; - - SIP.RegisterContext = RegisterContext; -}; - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* eslint-disable */ -/** - * @fileoverview SessionDescriptionHandler - */ - -/* SessionDescriptionHandler - * @class PeerConnection helper Class. - * @param {SIP.Session} session - * @param {Object} [options] - */ - -module.exports = function (EventEmitter) { - var SessionDescriptionHandler = function SessionDescriptionHandler(session, options) {}; - - SessionDescriptionHandler.prototype = Object.create(EventEmitter.prototype, { - - /** - * Destructor - */ - close: { value: function close() {} }, - - /** - * Gets the local description from the underlying media implementation - * @param {Object} [options] Options object to be used by getDescription - * @param {Array} [modifiers] Array with one time use description modifiers - * @returns {Promise} Promise that resolves with the local description to be used for the session - */ - getDescription: { value: function getDescription(options, modifiers) {} }, - - /** - * Check if the Session Description Handler can handle the Content-Type described by a SIP Message - * @param {String} contentType The content type that is in the SIP Message - * @returns {boolean} - */ - hasDescription: { value: function hasSessionDescription(contentType) {} }, - - /** - * The modifier that should be used when the session would like to place the call on hold - * @param {String} [sdp] The description that will be modified - * @returns {Promise} Promise that resolves with modified SDP - */ - holdModifier: { value: function holdModifier(sdp) {} }, - - /** - * Set the remote description to the underlying media implementation - * @param {String} sessionDescription The description provided by a SIP message to be set on the media implementation - * @param {Object} [options] Options object to be used by setDescription - * @param {Array} [modifiers] Array with one time use description modifiers - * @returns {Promise} Promise that resolves once the description is set - */ - setDescription: { value: function setDescription(sessionDescription, options, modifiers) {} } - }); - - return SessionDescriptionHandler; -}; - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function (SIP) { - var ClientContext; - - ClientContext = function ClientContext(ua, method, target, options) { - var originalTarget = target; - - // Validate arguments - if (target === undefined) { - throw new TypeError('Not enough arguments'); - } - - this.ua = ua; - this.logger = ua.getLogger('sip.clientcontext'); - this.method = method; - target = ua.normalizeTarget(target); - if (!target) { - throw new TypeError('Invalid target: ' + originalTarget); - } - - /* Options - * - extraHeaders - * - params - * - contentType - * - body - */ - options = Object.create(options || Object.prototype); - options.extraHeaders = (options.extraHeaders || []).slice(); - - // Build the request - this.request = new SIP.OutgoingRequest(this.method, target, this.ua, options.params, options.extraHeaders); - if (options.body) { - this.body = {}; - this.body.body = options.body; - if (options.contentType) { - this.body.contentType = options.contentType; - } - this.request.body = this.body; - } - - /* Set other properties from the request */ - this.localIdentity = this.request.from; - this.remoteIdentity = this.request.to; - - this.data = {}; - }; - ClientContext.prototype = Object.create(SIP.EventEmitter.prototype); - - ClientContext.prototype.send = function () { - new SIP.RequestSender(this, this.ua).send(); - return this; - }; - - ClientContext.prototype.cancel = function (options) { - options = options || {}; - - options.extraHeaders = (options.extraHeaders || []).slice(); - - var cancel_reason = SIP.Utils.getCancelReason(options.status_code, options.reason_phrase); - this.request.cancel(cancel_reason, options.extraHeaders); - - this.emit('cancel'); - }; - - ClientContext.prototype.receiveResponse = function (response) { - var cause = SIP.Utils.getReasonPhrase(response.status_code); - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - this.emit('progress', response, cause); - break; - - case /^2[0-9]{2}$/.test(response.status_code): - if (this.ua.applicants[this]) { - delete this.ua.applicants[this]; - } - this.emit('accepted', response, cause); - break; - - default: - if (this.ua.applicants[this]) { - delete this.ua.applicants[this]; - } - this.emit('rejected', response, cause); - this.emit('failed', response, cause); - break; - } - }; - - ClientContext.prototype.onRequestTimeout = function () { - this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT); - }; - - ClientContext.prototype.onTransportError = function () { - this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR); - }; - - SIP.ClientContext = ClientContext; -}; - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function (SIP) { - var ServerContext; - - ServerContext = function ServerContext(ua, request) { - this.ua = ua; - this.logger = ua.getLogger('sip.servercontext'); - this.request = request; - if (request.method === SIP.C.INVITE) { - this.transaction = new SIP.Transactions.InviteServerTransaction(request, ua); - } else { - this.transaction = new SIP.Transactions.NonInviteServerTransaction(request, ua); - } - - if (request.body) { - this.body = request.body; - } - if (request.hasHeader('Content-Type')) { - this.contentType = request.getHeader('Content-Type'); - } - this.method = request.method; - - this.data = {}; - - this.localIdentity = request.to; - this.remoteIdentity = request.from; - }; - - ServerContext.prototype = Object.create(SIP.EventEmitter.prototype); - - ServerContext.prototype.progress = function (options) { - options = Object.create(options || Object.prototype); - options.statusCode || (options.statusCode = 180); - options.minCode = 100; - options.maxCode = 199; - options.events = ['progress']; - return this.reply(options); - }; - - ServerContext.prototype.accept = function (options) { - options = Object.create(options || Object.prototype); - options.statusCode || (options.statusCode = 200); - options.minCode = 200; - options.maxCode = 299; - options.events = ['accepted']; - return this.reply(options); - }; - - ServerContext.prototype.reject = function (options) { - options = Object.create(options || Object.prototype); - options.statusCode || (options.statusCode = 480); - options.minCode = 300; - options.maxCode = 699; - options.events = ['rejected', 'failed']; - return this.reply(options); - }; - - ServerContext.prototype.reply = function (options) { - options = options || {}; // This is okay, so long as we treat options as read-only in this method - var statusCode = options.statusCode || 100, - minCode = options.minCode || 100, - maxCode = options.maxCode || 699, - reasonPhrase = SIP.Utils.getReasonPhrase(statusCode, options.reasonPhrase), - extraHeaders = options.extraHeaders || [], - body = options.body, - events = options.events || [], - response; - - if (statusCode < minCode || statusCode > maxCode) { - throw new TypeError('Invalid statusCode: ' + statusCode); - } - response = this.request.reply(statusCode, reasonPhrase, extraHeaders, body); - events.forEach(function (event) { - this.emit(event, response, reasonPhrase); - }, this); - - return this; - }; - - ServerContext.prototype.onRequestTimeout = function () { - this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT); - }; - - ServerContext.prototype.onTransportError = function () { - this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR); - }; - - SIP.ServerContext = ServerContext; -}; - -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function (SIP) { - - var DTMF = __webpack_require__(24)(SIP); - - var Session, - InviteServerContext, - InviteClientContext, - ReferServerContext, - ReferClientContext, - C = { - //Session states - STATUS_NULL: 0, - STATUS_INVITE_SENT: 1, - STATUS_1XX_RECEIVED: 2, - STATUS_INVITE_RECEIVED: 3, - STATUS_WAITING_FOR_ANSWER: 4, - STATUS_ANSWERED: 5, - STATUS_WAITING_FOR_PRACK: 6, - STATUS_WAITING_FOR_ACK: 7, - STATUS_CANCELED: 8, - STATUS_TERMINATED: 9, - STATUS_ANSWERED_WAITING_FOR_PRACK: 10, - STATUS_EARLY_MEDIA: 11, - STATUS_CONFIRMED: 12 - }; - - /* - * @param {function returning SIP.sessionDescriptionHandler} [sessionDescriptionHandlerFactory] - * (See the documentation for the sessionDescriptionHandlerFactory argument of the UA constructor.) - */ - Session = function Session(sessionDescriptionHandlerFactory) { - this.status = C.STATUS_NULL; - this.dialog = null; - this.pendingReinvite = false; - this.earlyDialogs = {}; - if (!sessionDescriptionHandlerFactory) { - throw new SIP.Exceptions.SessionDescriptionHandlerMissing('A session description handler is required for the session to function'); - } - this.sessionDescriptionHandlerFactory = sessionDescriptionHandlerFactory; - - this.hasOffer = false; - this.hasAnswer = false; - - // Session Timers - this.timers = { - ackTimer: null, - expiresTimer: null, - invite2xxTimer: null, - userNoAnswerTimer: null, - rel1xxTimer: null, - prackTimer: null - }; - - // Session info - this.startTime = null; - this.endTime = null; - this.tones = null; - - // Hold state - this.local_hold = false; - - // Flag to disable renegotiation. When set to true, it will not renegotiate - // and will throw a RENEGOTIATION_ERROR - this.disableRenegotiation = false; - - this.early_sdp = null; - this.rel100 = SIP.C.supported.UNSUPPORTED; - }; - - Session.prototype = { - dtmf: function dtmf(tones, options) { - var tone, - dtmfs = [], - self = this; - - options = options || {}; - - if (tones === undefined) { - throw new TypeError('Not enough arguments'); - } - - // Check Session Status - if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_WAITING_FOR_ACK) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - // Check tones - if (typeof tones !== 'string' && typeof tones !== 'number' || !tones.toString().match(/^[0-9A-D#*,]+$/i)) { - throw new TypeError('Invalid tones: ' + tones); - } - - tones = tones.toString().split(''); - - while (tones.length > 0) { - dtmfs.push(new DTMF(this, tones.shift(), options)); - } - - if (this.tones) { - // Tones are already queued, just add to the queue - this.tones = this.tones.concat(dtmfs); - return this; - } - - var sendDTMF = function sendDTMF() { - var dtmf, timeout; - - if (self.status === C.STATUS_TERMINATED || !self.tones || self.tones.length === 0) { - // Stop sending DTMF - self.tones = null; - return this; - } - - dtmf = self.tones.shift(); - - if (tone === ',') { - timeout = 2000; - } else { - dtmf.on('failed', function () { - self.tones = null; - }); - dtmf.send(options); - timeout = dtmf.duration + dtmf.interToneGap; - } - - // Set timeout for the next tone - SIP.Timers.setTimeout(sendDTMF, timeout); - }; - - this.tones = dtmfs; - sendDTMF(); - return this; - }, - - bye: function bye(options) { - options = Object.create(options || Object.prototype); - var statusCode = options.statusCode; - - // Check Session Status - if (this.status === C.STATUS_TERMINATED) { - this.logger.error('Error: Attempted to send BYE in a terminated session.'); - return this; - } - - this.logger.log('terminating Session'); - - if (statusCode && (statusCode < 200 || statusCode >= 700)) { - throw new TypeError('Invalid statusCode: ' + statusCode); - } - - options.receiveResponse = function () {}; - - return this.sendRequest(SIP.C.BYE, options).terminated(); - }, - - refer: function refer(target, options) { - options = options || {}; - - // Check Session Status - if (this.status !== C.STATUS_CONFIRMED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - this.referContext = new SIP.ReferClientContext(this.ua, this, target, options); - - this.emit('referRequested', this.referContext); - - this.referContext.refer(); - }, - - sendRequest: function sendRequest(method, options) { - options = options || {}; - var self = this; - - var request = new SIP.OutgoingRequest(method, this.dialog.remote_target, this.ua, { - cseq: options.cseq || (this.dialog.local_seqnum += 1), - call_id: this.dialog.id.call_id, - from_uri: this.dialog.local_uri, - from_tag: this.dialog.id.local_tag, - to_uri: this.dialog.remote_uri, - to_tag: this.dialog.id.remote_tag, - route_set: this.dialog.route_set, - statusCode: options.statusCode, - reasonPhrase: options.reasonPhrase - }, options.extraHeaders || [], options.body); - - new SIP.RequestSender({ - request: request, - onRequestTimeout: function onRequestTimeout() { - self.onRequestTimeout(); - }, - onTransportError: function onTransportError() { - self.onTransportError(); - }, - receiveResponse: options.receiveResponse || function (response) { - self.receiveNonInviteResponse(response); - } - }, this.ua).send(); - - // Emit the request event - this.emit(method.toLowerCase(), request); - - return this; - }, - - close: function close() { - var idx; - - if (this.status === C.STATUS_TERMINATED) { - return this; - } - - this.logger.log('closing INVITE session ' + this.id); - - // 1st Step. Terminate media. - if (this.sessionDescriptionHandler) { - this.sessionDescriptionHandler.close(); - } - - // 2nd Step. Terminate signaling. - - // Clear session timers - for (idx in this.timers) { - SIP.Timers.clearTimeout(this.timers[idx]); - } - - // Terminate dialogs - - // Terminate confirmed dialog - if (this.dialog) { - this.dialog.terminate(); - delete this.dialog; - } - - // Terminate early dialogs - for (idx in this.earlyDialogs) { - this.earlyDialogs[idx].terminate(); - delete this.earlyDialogs[idx]; - } - - this.status = C.STATUS_TERMINATED; - - delete this.ua.sessions[this.id]; - return this; - }, - - createDialog: function createDialog(message, type, early) { - var dialog, - early_dialog, - local_tag = message[type === 'UAS' ? 'to_tag' : 'from_tag'], - remote_tag = message[type === 'UAS' ? 'from_tag' : 'to_tag'], - id = message.call_id + local_tag + remote_tag; - - early_dialog = this.earlyDialogs[id]; - - // Early Dialog - if (early) { - if (early_dialog) { - return true; - } else { - early_dialog = new SIP.Dialog(this, message, type, SIP.Dialog.C.STATUS_EARLY); - - // Dialog has been successfully created. - if (early_dialog.error) { - this.logger.error(early_dialog.error); - this.failed(message, SIP.C.causes.INTERNAL_ERROR); - return false; - } else { - this.earlyDialogs[id] = early_dialog; - return true; - } - } - } - // Confirmed Dialog - else { - // In case the dialog is in _early_ state, update it - if (early_dialog) { - early_dialog.update(message, type); - this.dialog = early_dialog; - delete this.earlyDialogs[id]; - for (var dia in this.earlyDialogs) { - this.earlyDialogs[dia].terminate(); - delete this.earlyDialogs[dia]; - } - return true; - } - - // Otherwise, create a _confirmed_ dialog - dialog = new SIP.Dialog(this, message, type); - - if (dialog.error) { - this.logger.error(dialog.error); - this.failed(message, SIP.C.causes.INTERNAL_ERROR); - return false; - } else { - this.to_tag = message.to_tag; - this.dialog = dialog; - return true; - } - } - }, - - /** - * Hold - */ - hold: function hold(options, modifiers) { - - if (this.status !== C.STATUS_WAITING_FOR_ACK && this.status !== C.STATUS_CONFIRMED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - if (this.local_hold) { - this.logger.log('Session is already on hold, cannot put it on hold again'); - return; - } - - options = options || {}; - options.modifiers = modifiers || []; - options.modifiers.push(this.sessionDescriptionHandler.holdModifier); - - this.local_hold = true; - - this.sendReinvite(options); - }, - - /** - * Unhold - */ - unhold: function unhold(options, modifiers) { - - if (this.status !== C.STATUS_WAITING_FOR_ACK && this.status !== C.STATUS_CONFIRMED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - if (!this.local_hold) { - this.logger.log('Session is not on hold, cannot unhold it'); - return; - } - - options = options || {}; - - if (modifiers) { - options.modifiers = modifiers; - } - - this.local_hold = false; - - this.sendReinvite(options); - }, - - reinvite: function reinvite(options, modifiers) { - options = options || {}; - - if (modifiers) { - options.modifiers = modifiers; - } - - return this.sendReinvite(options); - }, - - /** - * In dialog INVITE Reception - * @private - */ - receiveReinvite: function receiveReinvite(request) { - var self = this, - promise; - // TODO: Should probably check state of the session - - self.emit('reinvite', this); - - // Invite w/o SDP - if (request.getHeader('Content-Length') === '0' && !request.getHeader('Content-Type')) { - promise = this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions, this.modifiers); - - // Invite w/ SDP - } else if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) { - promise = this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler, this.sessionDescriptionHandlerOptions, this.modifiers)); - - // Bad Packet (should never get hit) - } else { - request.reply(415); - this.emit('reinviteFailed', self); - return; - } - - var _receiveRequest = this.receiveRequest; - - // HACK to catch the ACK - this.receiveRequest = function (request) { - if (request.method === SIP.C.ACK && this.status === C.STATUS_WAITING_FOR_ACK && this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) { - this.hasAnswer = true; - this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function () { - SIP.Timers.clearTimeout(this.timers.ackTimer); - SIP.Timers.clearTimeout(this.timers.invite2xxTimer); - this.status = C.STATUS_CONFIRMED; - - this.emit('confirmed', request); - }.bind(this)); - } else { - _receiveRequest.call(this, request); - } - }.bind(this); - - promise.catch(function onFailure(e) { - var statusCode; - if (e instanceof SIP.Exceptions.GetDescriptionError) { - statusCode = 500; - } else if (e instanceof SIP.Exceptions.RenegotiationError) { - self.emit('renegotiationError', e); - self.logger.warn(e); - statusCode = 488; - } else { - self.logger.error(e); - statusCode = 488; - } - request.reply(statusCode); - self.emit('reinviteFailed', self); - }).then(function (description) { - var extraHeaders = ['Contact: ' + self.contact]; - request.reply(200, null, extraHeaders, description, function () { - self.status = C.STATUS_WAITING_FOR_ACK; - - self.setACKTimer(); - self.emit('reinviteAccepted', self); - }); - }); - }, - - sendReinvite: function sendReinvite(options) { - if (this.pendingReinvite) { - this.logger.warn('Reinvite in progress. Please wait until complete, then try again.'); - return; - } - this.pendingReinvite = true; - options = options || {}; - options.modifiers = options.modifiers || []; - - var self = this, - extraHeaders = (options.extraHeaders || []).slice(); - - extraHeaders.push('Contact: ' + this.contact); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers).then(function (description) { - self.sendRequest(SIP.C.INVITE, { - extraHeaders: extraHeaders, - body: description, - receiveResponse: self.receiveReinviteResponse.bind(self) - }); - }).catch(function onFailure(e) { - if (e instanceof SIP.Exceptions.RenegotiationError) { - self.pendingReinvite = false; - self.emit('renegotiationError', e); - self.logger.warn('Renegotiation Error'); - self.logger.warn(e); - return; - } - self.logger.error('sessionDescriptionHandler error'); - self.logger.error(e); - }); - }, - - receiveRequest: function receiveRequest(request) { - switch (request.method) { - case SIP.C.BYE: - request.reply(200); - if (this.status === C.STATUS_CONFIRMED) { - this.emit('bye', request); - this.terminated(request, SIP.C.causes.BYE); - } - break; - case SIP.C.INVITE: - if (this.status === C.STATUS_CONFIRMED) { - this.logger.log('re-INVITE received'); - this.receiveReinvite(request); - } - break; - case SIP.C.INFO: - if (this.status === C.STATUS_CONFIRMED || this.status === C.STATUS_WAITING_FOR_ACK) { - if (this.onInfo) { - return this.onInfo(request); - } - - var body, - tone, - duration, - contentType = request.getHeader('content-type'), - reg_tone = /^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/, - reg_duration = /^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/; - - if (contentType) { - if (contentType.match(/^application\/dtmf-relay/i)) { - if (request.body) { - body = request.body.split('\r\n', 2); - if (body.length === 2) { - if (reg_tone.test(body[0])) { - tone = body[0].replace(reg_tone, "$2"); - } - if (reg_duration.test(body[1])) { - duration = parseInt(body[1].replace(reg_duration, "$2"), 10); - } - } - } - - new DTMF(this, tone, { duration: duration }).init_incoming(request); - } else { - request.reply(415, null, ["Accept: application/dtmf-relay"]); - } - } - } - break; - case SIP.C.REFER: - if (this.status === C.STATUS_CONFIRMED) { - this.logger.log('REFER received'); - this.referContext = new SIP.ReferServerContext(this.ua, request); - var hasReferListener = this.listeners('referRequested').length; - if (hasReferListener) { - this.emit('referRequested', this.referContext); - } else { - this.logger.log('No referRequested listeners, automatically accepting and following the refer'); - var options = { followRefer: true }; - if (this.passedOptions) { - options.inviteOptions = this.passedOptions; - } - this.referContext.accept(options, this.modifiers); - } - } - break; - case SIP.C.NOTIFY: - if (this.referContext && this.referContext instanceof SIP.ReferClientContext && request.hasHeader('event') && request.getHeader('event') === 'refer') { - this.referContext.receiveNotify(request); - return; - } - request.reply(200, 'OK'); - this.emit('notify', request); - break; - } - }, - - /** - * Reception of Response for in-dialog INVITE - * @private - */ - receiveReinviteResponse: function receiveReinviteResponse(response) { - var self = this; - - if (this.status === C.STATUS_TERMINATED) { - return; - } - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - break; - case /^2[0-9]{2}$/.test(response.status_code): - this.status = C.STATUS_CONFIRMED; - - // 17.1.1.1 - For each final response that is received at the client transaction, the client transaction sends an ACK, - this.emit("ack", response.transaction.sendACK()); - this.pendingReinvite = false; - // TODO: All of these timers should move into the Transaction layer - SIP.Timers.clearTimeout(self.timers.invite2xxTimer); - if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) { - this.logger.error('2XX response received to re-invite but did not have a description'); - this.emit('renegotiationError', new SIP.Exceptions.RenegotiationError('2XX response received to re-invite but did not have a description')); - - break; - } - - this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).catch(function onFailure(e) { - self.logger.error('Could not set the description in 2XX response'); - self.logger.error(e); - self.emit('renegotiationError', e); - self.sendRequest(SIP.C.BYE, { - extraHeaders: [SIP.Utils.getReasonHeaderValue(488, 'Not Acceptable Here')] - }); - }); - break; - default: - this.disableRenegotiation = true; - this.pendingReinvite = false; - this.logger.log('Received a non 1XX or 2XX response to a re-invite'); - this.emit('renegotiationError', new SIP.Exceptions.RenegotiationError('Invalid response to a re-invite')); - } - }, - - acceptAndTerminate: function acceptAndTerminate(response, status_code, reason_phrase) { - var extraHeaders = []; - - if (status_code) { - extraHeaders.push('Reason: ' + SIP.Utils.getReasonHeaderValue(status_code, reason_phrase)); - } - - // An error on dialog creation will fire 'failed' event - if (this.dialog || this.createDialog(response, 'UAC')) { - this.emit("ack", response.transaction.sendACK()); - this.sendRequest(SIP.C.BYE, { - extraHeaders: extraHeaders - }); - } - - return this; - }, - - /** - * RFC3261 13.3.1.4 - * Response retransmissions cannot be accomplished by transaction layer - * since it is destroyed when receiving the first 2xx answer - */ - setInvite2xxTimer: function setInvite2xxTimer(request, description) { - var self = this, - timeout = SIP.Timers.T1; - - this.timers.invite2xxTimer = SIP.Timers.setTimeout(function invite2xxRetransmission() { - if (self.status !== C.STATUS_WAITING_FOR_ACK) { - return; - } - - self.logger.log('no ACK received, attempting to retransmit OK'); - - var extraHeaders = ['Contact: ' + self.contact]; - - request.reply(200, null, extraHeaders, description); - - timeout = Math.min(timeout * 2, SIP.Timers.T2); - - self.timers.invite2xxTimer = SIP.Timers.setTimeout(invite2xxRetransmission, timeout); - }, timeout); - }, - - /** - * RFC3261 14.2 - * If a UAS generates a 2xx response and never receives an ACK, - * it SHOULD generate a BYE to terminate the dialog. - */ - setACKTimer: function setACKTimer() { - var self = this; - - this.timers.ackTimer = SIP.Timers.setTimeout(function () { - if (self.status === C.STATUS_WAITING_FOR_ACK) { - self.logger.log('no ACK received for an extended period of time, terminating the call'); - SIP.Timers.clearTimeout(self.timers.invite2xxTimer); - self.sendRequest(SIP.C.BYE); - self.terminated(null, SIP.C.causes.NO_ACK); - } - }, SIP.Timers.TIMER_H); - }, - - /* - * @private - */ - onTransportError: function onTransportError() { - if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.CONNECTION_ERROR); - } - }, - - onRequestTimeout: function onRequestTimeout() { - if (this.status === C.STATUS_CONFIRMED) { - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } else if (this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.REQUEST_TIMEOUT); - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } - }, - - onDialogError: function onDialogError(response) { - if (this.status === C.STATUS_CONFIRMED) { - this.terminated(response, SIP.C.causes.DIALOG_ERROR); - } else if (this.status !== C.STATUS_TERMINATED) { - this.failed(response, SIP.C.causes.DIALOG_ERROR); - this.terminated(response, SIP.C.causes.DIALOG_ERROR); - } - }, - - /** - * @private - */ - - failed: function failed(response, cause) { - if (this.status === C.STATUS_TERMINATED) { - return this; - } - this.emit('failed', response || null, cause || null); - return this; - }, - - rejected: function rejected(response, cause) { - this.emit('rejected', response || null, cause || null); - return this; - }, - - canceled: function canceled() { - this.emit('cancel'); - return this; - }, - - accepted: function accepted(response, cause) { - cause = SIP.Utils.getReasonPhrase(response && response.status_code, cause); - - this.startTime = new Date(); - - if (this.replacee) { - this.replacee.emit('replaced', this); - this.replacee.terminate(); - } - this.emit('accepted', response, cause); - return this; - }, - - terminated: function terminated(message, cause) { - if (this.status === C.STATUS_TERMINATED) { - return this; - } - - this.endTime = new Date(); - - this.close(); - this.emit('terminated', message || null, cause || null); - return this; - }, - - connecting: function connecting(request) { - this.emit('connecting', { request: request }); - return this; - } - }; - - Session.C = C; - SIP.Session = Session; - - InviteServerContext = function InviteServerContext(ua, request) { - var expires, - self = this, - contentType = request.getHeader('Content-Type'), - contentDisp = request.parseHeader('Content-Disposition'); - - SIP.Utils.augment(this, SIP.ServerContext, [ua, request]); - SIP.Utils.augment(this, SIP.Session, [ua.configuration.sessionDescriptionHandlerFactory]); - - if (contentDisp && contentDisp.type === 'render') { - this.renderbody = request.body; - this.rendertype = contentType; - } - - this.status = C.STATUS_INVITE_RECEIVED; - this.from_tag = request.from_tag; - this.id = request.call_id + this.from_tag; - this.request = request; - this.contact = this.ua.contact.toString(); - - this.receiveNonInviteResponse = function () {}; // intentional no-op - - this.logger = ua.getLogger('sip.inviteservercontext', this.id); - - //Save the session into the ua sessions collection. - this.ua.sessions[this.id] = this; - - //Get the Expires header value if exists - if (request.hasHeader('expires')) { - expires = request.getHeader('expires') * 1000; - } - - //Set 100rel if necessary - function set100rel(h, c) { - if (request.hasHeader(h) && request.getHeader(h).toLowerCase().indexOf('100rel') >= 0) { - self.rel100 = c; - } - } - set100rel('require', SIP.C.supported.REQUIRED); - set100rel('supported', SIP.C.supported.SUPPORTED); - - /* Set the to_tag before - * replying a response code that will create a dialog. - */ - request.to_tag = SIP.Utils.newTag(); - - // An error on dialog creation will fire 'failed' event - if (!this.createDialog(request, 'UAS', true)) { - request.reply(500, 'Missing Contact header field'); - return; - } - - var options = { extraHeaders: ['Contact: ' + self.contact] }; - - if (self.rel100 !== SIP.C.supported.REQUIRED) { - self.progress(options); - } - self.status = C.STATUS_WAITING_FOR_ANSWER; - - // Set userNoAnswerTimer - self.timers.userNoAnswerTimer = SIP.Timers.setTimeout(function () { - request.reply(408); - self.failed(request, SIP.C.causes.NO_ANSWER); - self.terminated(request, SIP.C.causes.NO_ANSWER); - }, self.ua.configuration.noAnswerTimeout); - - /* Set expiresTimer - * RFC3261 13.3.1 - */ - if (expires) { - self.timers.expiresTimer = SIP.Timers.setTimeout(function () { - if (self.status === C.STATUS_WAITING_FOR_ANSWER) { - request.reply(487); - self.failed(request, SIP.C.causes.EXPIRES); - self.terminated(request, SIP.C.causes.EXPIRES); - } - }, expires); - } - }; - - InviteServerContext.prototype = { - reject: function reject(options) { - // Check Session Status - if (this.status === C.STATUS_TERMINATED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - this.logger.log('rejecting RTCSession'); - - SIP.ServerContext.prototype.reject.call(this, options); - return this.terminated(); - }, - - terminate: function terminate(options) { - options = options || {}; - - var extraHeaders = (options.extraHeaders || []).slice(), - body = options.body, - dialog, - self = this; - - if (this.status === C.STATUS_WAITING_FOR_ACK && this.request.server_transaction.state !== SIP.Transactions.C.STATUS_TERMINATED) { - dialog = this.dialog; - - this.receiveRequest = function (request) { - if (request.method === SIP.C.ACK) { - this.sendRequest(SIP.C.BYE, { - extraHeaders: extraHeaders, - body: body - }); - dialog.terminate(); - } - }; - - this.request.server_transaction.on('stateChanged', function () { - if (this.state === SIP.Transactions.C.STATUS_TERMINATED && this.dialog) { - this.request = new SIP.OutgoingRequest(SIP.C.BYE, this.dialog.remote_target, this.ua, { - 'cseq': this.dialog.local_seqnum += 1, - 'call_id': this.dialog.id.call_id, - 'from_uri': this.dialog.local_uri, - 'from_tag': this.dialog.id.local_tag, - 'to_uri': this.dialog.remote_uri, - 'to_tag': this.dialog.id.remote_tag, - 'route_set': this.dialog.route_set - }, extraHeaders, body); - - new SIP.RequestSender({ - request: this.request, - onRequestTimeout: function onRequestTimeout() { - self.onRequestTimeout(); - }, - onTransportError: function onTransportError() { - self.onTransportError(); - }, - receiveResponse: function receiveResponse() { - return; - } - }, this.ua).send(); - dialog.terminate(); - } - }); - - this.emit('bye', this.request); - this.terminated(); - - // Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-) - this.dialog = dialog; - - // Restore the dialog into 'ua' so the ACK can reach 'this' session - this.ua.dialogs[dialog.id.toString()] = dialog; - } else if (this.status === C.STATUS_CONFIRMED) { - this.bye(options); - } else { - this.reject(options); - } - - return this; - }, - - /* - * @param {Object} [options.sessionDescriptionHandlerOptions] gets passed to SIP.SessionDescriptionHandler.getDescription as options - */ - progress: function progress(options) { - options = options || {}; - var statusCode = options.statusCode || 180, - reasonPhrase = options.reasonPhrase, - extraHeaders = (options.extraHeaders || []).slice(), - body = options.body, - response; - - if (statusCode < 100 || statusCode > 199) { - throw new TypeError('Invalid statusCode: ' + statusCode); - } - - if (this.isCanceled || this.status === C.STATUS_TERMINATED) { - return this; - } - - function do100rel() { - /* jshint validthis: true */ - statusCode = options.statusCode || 183; - - // Set status and add extra headers - this.status = C.STATUS_WAITING_FOR_PRACK; - extraHeaders.push('Contact: ' + this.contact); - extraHeaders.push('Require: 100rel'); - extraHeaders.push('RSeq: ' + Math.floor(Math.random() * 10000)); - - // Get the session description to add to preaccept with - this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers).then(function onSuccess(description) { - if (this.isCanceled || this.status === C.STATUS_TERMINATED) { - return; - } - - this.early_sdp = description.body; - this[this.hasOffer ? 'hasAnswer' : 'hasOffer'] = true; - - // Retransmit until we get a response or we time out (see prackTimer below) - var timeout = SIP.Timers.T1; - this.timers.rel1xxTimer = SIP.Timers.setTimeout(function rel1xxRetransmission() { - this.request.reply(statusCode, null, extraHeaders, description); - timeout *= 2; - this.timers.rel1xxTimer = SIP.Timers.setTimeout(rel1xxRetransmission.bind(this), timeout); - }.bind(this), timeout); - - // Timeout and reject INVITE if no response - this.timers.prackTimer = SIP.Timers.setTimeout(function () { - if (this.status !== C.STATUS_WAITING_FOR_PRACK) { - return; - } - - this.logger.log('no PRACK received, rejecting the call'); - SIP.Timers.clearTimeout(this.timers.rel1xxTimer); - this.request.reply(504); - this.terminated(null, SIP.C.causes.NO_PRACK); - }.bind(this), SIP.Timers.T1 * 64); - - // Send the initial response - response = this.request.reply(statusCode, reasonPhrase, extraHeaders, description); - this.emit('progress', response, reasonPhrase); - }.bind(this), function onFailure() { - this.request.reply(480); - this.failed(null, SIP.C.causes.WEBRTC_ERROR); - this.terminated(null, SIP.C.causes.WEBRTC_ERROR); - }.bind(this)); - } // end do100rel - - function normalReply() { - /* jshint validthis:true */ - response = this.request.reply(statusCode, reasonPhrase, extraHeaders, body); - this.emit('progress', response, reasonPhrase); - } - - if (options.statusCode !== 100 && (this.rel100 === SIP.C.supported.REQUIRED || this.rel100 === SIP.C.supported.SUPPORTED && options.rel100 || this.rel100 === SIP.C.supported.SUPPORTED && this.ua.configuration.rel100 === SIP.C.supported.REQUIRED)) { - this.sessionDescriptionHandler = this.setupSessionDescriptionHandler(); - if (this.sessionDescriptionHandler.hasDescription(this.request.getHeader('Content-Type'))) { - this.hasOffer = true; - this.sessionDescriptionHandler.setDescription(this.request.body, options.sessionDescriptionHandlerOptions, options.modifiers).then(do100rel.apply(this)).catch(function onFailure(e) { - this.logger.warn('invalid description'); - this.logger.warn(e); - this.failed(null, SIP.C.causes.WEBRTC_ERROR); - this.terminated(null, SIP.C.causes.WEBRTC_ERROR); - }.bind(this)); - } else { - do100rel.apply(this); - } - } else { - normalReply.apply(this); - } - return this; - }, - - /* - * @param {Object} [options.sessionDescriptionHandlerOptions] gets passed to SIP.SessionDescriptionHandler.getDescription as options - */ - accept: function accept(options) { - options = options || {}; - - this.onInfo = options.onInfo; - - var self = this, - request = this.request, - extraHeaders = (options.extraHeaders || []).slice(), - descriptionCreationSucceeded = function descriptionCreationSucceeded(description) { - var response, - - // run for reply success callback - replySucceeded = function replySucceeded() { - self.status = C.STATUS_WAITING_FOR_ACK; - - self.setInvite2xxTimer(request, description); - self.setACKTimer(); - }, - - - // run for reply failure callback - replyFailed = function replyFailed() { - self.failed(null, SIP.C.causes.CONNECTION_ERROR); - self.terminated(null, SIP.C.causes.CONNECTION_ERROR); - }; - - extraHeaders.push('Contact: ' + self.contact); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - if (!self.hasOffer) { - self.hasOffer = true; - } else { - self.hasAnswer = true; - } - response = request.reply(200, null, extraHeaders, description, replySucceeded, replyFailed); - if (self.status !== C.STATUS_TERMINATED) { - // Didn't fail - self.accepted(response, SIP.Utils.getReasonPhrase(200)); - } - }, - descriptionCreationFailed = function descriptionCreationFailed() { - // TODO: This should check the actual error and make sure it is an - // "expected" error. Otherwise it should throw. - if (self.status === C.STATUS_TERMINATED) { - return; - } - self.request.reply(480); - self.failed(null, SIP.C.causes.WEBRTC_ERROR); - self.terminated(null, SIP.C.causes.WEBRTC_ERROR); - }; - - // Check Session Status - if (this.status === C.STATUS_WAITING_FOR_PRACK) { - this.status = C.STATUS_ANSWERED_WAITING_FOR_PRACK; - return this; - } else if (this.status === C.STATUS_WAITING_FOR_ANSWER) { - this.status = C.STATUS_ANSWERED; - } else if (this.status !== C.STATUS_EARLY_MEDIA) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - // An error on dialog creation will fire 'failed' event - if (!this.createDialog(request, 'UAS')) { - request.reply(500, 'Missing Contact header field'); - return this; - } - - SIP.Timers.clearTimeout(this.timers.userNoAnswerTimer); - - if (this.status === C.STATUS_EARLY_MEDIA) { - descriptionCreationSucceeded({}); - } else { - this.sessionDescriptionHandler = this.setupSessionDescriptionHandler(); - if (this.request.getHeader('Content-Length') === '0' && !this.request.getHeader('Content-Type')) { - this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers).catch(descriptionCreationFailed).then(descriptionCreationSucceeded); - } else if (this.sessionDescriptionHandler.hasDescription(this.request.getHeader('Content-Type'))) { - this.hasOffer = true; - this.sessionDescriptionHandler.setDescription(this.request.body, options.sessionDescriptionHandlerOptions, options.modifiers).then(function () { - return this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers); - }.bind(this)).catch(descriptionCreationFailed).then(descriptionCreationSucceeded); - } else { - this.request.reply(415); - // TODO: Events - return; - } - } - - return this; - }, - - receiveRequest: function receiveRequest(request) { - - // ISC RECEIVE REQUEST - - function confirmSession() { - /* jshint validthis:true */ - var contentType, contentDisp; - - SIP.Timers.clearTimeout(this.timers.ackTimer); - SIP.Timers.clearTimeout(this.timers.invite2xxTimer); - this.status = C.STATUS_CONFIRMED; - - contentType = request.getHeader('Content-Type'); - contentDisp = request.getHeader('Content-Disposition'); - - if (contentDisp && contentDisp.type === 'render') { - this.renderbody = request.body; - this.rendertype = contentType; - } - - this.emit('confirmed', request); - } - - switch (request.method) { - case SIP.C.CANCEL: - /* RFC3261 15 States that a UAS may have accepted an invitation while a CANCEL - * was in progress and that the UAC MAY continue with the session established by - * any 2xx response, or MAY terminate with BYE. SIP does continue with the - * established session. So the CANCEL is processed only if the session is not yet - * established. - */ - - /* - * Terminate the whole session in case the user didn't accept (or yet to send the answer) nor reject the - *request opening the session. - */ - if (this.status === C.STATUS_WAITING_FOR_ANSWER || this.status === C.STATUS_WAITING_FOR_PRACK || this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK || this.status === C.STATUS_EARLY_MEDIA || this.status === C.STATUS_ANSWERED) { - - this.status = C.STATUS_CANCELED; - this.request.reply(487); - this.canceled(request); - this.rejected(request, SIP.C.causes.CANCELED); - this.failed(request, SIP.C.causes.CANCELED); - this.terminated(request, SIP.C.causes.CANCELED); - } - break; - case SIP.C.ACK: - if (this.status === C.STATUS_WAITING_FOR_ACK) { - if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) { - // ACK contains answer to an INVITE w/o SDP negotiation - this.hasAnswer = true; - this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then( - // TODO: Catch then .then - confirmSession.bind(this), function onFailure(e) { - this.logger.warn(e); - this.terminate({ - statusCode: '488', - reasonPhrase: 'Bad Media Description' - }); - this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - }.bind(this)); - } else { - confirmSession.apply(this); - } - } - break; - case SIP.C.PRACK: - if (this.status === C.STATUS_WAITING_FOR_PRACK || this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) { - if (!this.hasAnswer) { - this.sessionDescriptionHandler = this.setupSessionDescriptionHandler(); - if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) { - this.hasAnswer = true; - this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function onSuccess() { - SIP.Timers.clearTimeout(this.timers.rel1xxTimer); - SIP.Timers.clearTimeout(this.timers.prackTimer); - request.reply(200); - if (this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) { - this.status = C.STATUS_EARLY_MEDIA; - this.accept(); - } - this.status = C.STATUS_EARLY_MEDIA; - }.bind(this), function onFailure(e) { - this.logger.warn(e); - this.terminate({ - statusCode: '488', - reasonPhrase: 'Bad Media Description' - }); - this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - }.bind(this)); - } else { - this.terminate({ - statusCode: '488', - reasonPhrase: 'Bad Media Description' - }); - this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - } - } else { - SIP.Timers.clearTimeout(this.timers.rel1xxTimer); - SIP.Timers.clearTimeout(this.timers.prackTimer); - request.reply(200); - - if (this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) { - this.status = C.STATUS_EARLY_MEDIA; - this.accept(); - } - this.status = C.STATUS_EARLY_MEDIA; - } - } else if (this.status === C.STATUS_EARLY_MEDIA) { - request.reply(200); - } - break; - default: - Session.prototype.receiveRequest.apply(this, [request]); - break; - } - }, - - // Internal Function to setup the handler consistently - setupSessionDescriptionHandler: function setupSessionDescriptionHandler() { - if (this.sessionDescriptionHandler) { - return this.sessionDescriptionHandler; - } - return this.sessionDescriptionHandlerFactory(this, this.ua.configuration.sessionDescriptionHandlerFactoryOptions); - }, - - onTransportError: function onTransportError() { - if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.CONNECTION_ERROR); - } - }, - - onRequestTimeout: function onRequestTimeout() { - if (this.status === C.STATUS_CONFIRMED) { - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } else if (this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.REQUEST_TIMEOUT); - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } - } - - }; - - SIP.InviteServerContext = InviteServerContext; - - InviteClientContext = function InviteClientContext(ua, target, options, modifiers) { - options = options || {}; - this.passedOptions = options; // Save for later to use with refer - options.params = Object.create(options.params || Object.prototype); - - var extraHeaders = (options.extraHeaders || []).slice(), - sessionDescriptionHandlerFactory = ua.configuration.sessionDescriptionHandlerFactory; - - this.sessionDescriptionHandlerFactoryOptions = ua.configuration.sessionDescriptionHandlerFactoryOptions || {}; - this.sessionDescriptionHandlerOptions = options.sessionDescriptionHandlerOptions || {}; - this.modifiers = modifiers; - - this.inviteWithoutSdp = options.inviteWithoutSdp || false; - - // Set anonymous property - this.anonymous = options.anonymous || false; - - // Custom data to be sent either in INVITE or in ACK - this.renderbody = options.renderbody || null; - this.rendertype = options.rendertype || 'text/plain'; - - // Session parameter initialization - this.from_tag = SIP.Utils.newTag(); - options.params.from_tag = this.from_tag; - - /* Do not add ;ob in initial forming dialog requests if the registration over - * the current connection got a GRUU URI. - */ - this.contact = ua.contact.toString({ - anonymous: this.anonymous, - outbound: this.anonymous ? !ua.contact.temp_gruu : !ua.contact.pub_gruu - }); - - if (this.anonymous) { - options.params.from_displayName = 'Anonymous'; - options.params.from_uri = 'sip:anonymous@anonymous.invalid'; - - extraHeaders.push('P-Preferred-Identity: ' + ua.configuration.uri.toString()); - extraHeaders.push('Privacy: id'); - } - extraHeaders.push('Contact: ' + this.contact); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - if (this.inviteWithoutSdp && this.renderbody) { - extraHeaders.push('Content-Type: ' + this.rendertype); - extraHeaders.push('Content-Disposition: render;handling=optional'); - } - - if (ua.configuration.rel100 === SIP.C.supported.REQUIRED) { - extraHeaders.push('Require: 100rel'); - } - if (ua.configuration.replaces === SIP.C.supported.REQUIRED) { - extraHeaders.push('Require: replaces'); - } - - options.extraHeaders = extraHeaders; - - SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.INVITE, target, options]); - SIP.Utils.augment(this, SIP.Session, [sessionDescriptionHandlerFactory]); - - // Check Session Status - if (this.status !== C.STATUS_NULL) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - // OutgoingSession specific parameters - this.isCanceled = false; - this.received_100 = false; - - this.method = SIP.C.INVITE; - - this.receiveNonInviteResponse = this.receiveResponse; - this.receiveResponse = this.receiveInviteResponse; - - this.logger = ua.getLogger('sip.inviteclientcontext'); - - ua.applicants[this] = this; - - this.id = this.request.call_id + this.from_tag; - - this.onInfo = options.onInfo; - }; - - InviteClientContext.prototype = { - invite: function invite() { - var self = this; - - //Save the session into the ua sessions collection. - //Note: placing in constructor breaks call to request.cancel on close... User does not need this anyway - this.ua.sessions[this.id] = this; - - if (this.inviteWithoutSdp) { - //just send an invite with no sdp... - this.request.body = self.renderbody; - this.status = C.STATUS_INVITE_SENT; - this.send(); - } else { - //Initialize Media Session - this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions); - - this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions, this.modifiers).then(function onSuccess(description) { - if (self.isCanceled || self.status === C.STATUS_TERMINATED) { - return; - } - self.hasOffer = true; - self.request.body = description; - self.status = C.STATUS_INVITE_SENT; - self.send(); - }, function onFailure() { - if (self.status === C.STATUS_TERMINATED) { - return; - } - self.failed(null, SIP.C.causes.WEBRTC_ERROR); - self.terminated(null, SIP.C.causes.WEBRTC_ERROR); - }); - } - - return this; - }, - - receiveInviteResponse: function receiveInviteResponse(response) { - var cause, - session = this, - id = response.call_id + response.from_tag + response.to_tag, - extraHeaders = [], - options = {}; - - if (this.status === C.STATUS_TERMINATED || response.method !== SIP.C.INVITE) { - return; - } - - if (this.dialog && response.status_code >= 200 && response.status_code <= 299) { - if (id !== this.dialog.id.toString()) { - if (!this.createDialog(response, 'UAC', true)) { - return; - } - this.emit("ack", response.transaction.sendACK({ body: SIP.Utils.generateFakeSDP(response.body) })); - this.earlyDialogs[id].sendRequest(this, SIP.C.BYE); - - /* NOTE: This fails because the forking proxy does not recognize that an unanswerable - * leg (due to peerConnection limitations) has been answered first. If your forking - * proxy does not hang up all unanswered branches on the first branch answered, remove this. - */ - if (this.status !== C.STATUS_CONFIRMED) { - this.failed(response, SIP.C.causes.WEBRTC_ERROR); - this.terminated(response, SIP.C.causes.WEBRTC_ERROR); - } - return; - } else if (this.status === C.STATUS_CONFIRMED) { - this.emit("ack", response.transaction.sendACK()); - return; - } else if (!this.hasAnswer) { - // invite w/o sdp is waiting for callback - //an invite with sdp must go on, and hasAnswer is true - return; - } - } - - if (this.dialog && response.status_code < 200) { - /* - Early media has been set up with at least one other different branch, - but a final 2xx response hasn't been received - */ - if (this.dialog.pracked.indexOf(response.getHeader('rseq')) !== -1 || this.dialog.pracked[this.dialog.pracked.length - 1] >= response.getHeader('rseq') && this.dialog.pracked.length > 0) { - return; - } - - if (!this.earlyDialogs[id] && !this.createDialog(response, 'UAC', true)) { - return; - } - - if (this.earlyDialogs[id].pracked.indexOf(response.getHeader('rseq')) !== -1 || this.earlyDialogs[id].pracked[this.earlyDialogs[id].pracked.length - 1] >= response.getHeader('rseq') && this.earlyDialogs[id].pracked.length > 0) { - return; - } - - extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq')); - this.earlyDialogs[id].pracked.push(response.getHeader('rseq')); - - this.earlyDialogs[id].sendRequest(this, SIP.C.PRACK, { - extraHeaders: extraHeaders, - body: SIP.Utils.generateFakeSDP(response.body) - }); - return; - } - - // Proceed to cancellation if the user requested. - if (this.isCanceled) { - if (response.status_code >= 100 && response.status_code < 200) { - this.request.cancel(this.cancelReason, extraHeaders); - this.canceled(null); - } else if (response.status_code >= 200 && response.status_code < 299) { - this.acceptAndTerminate(response); - this.emit('bye', this.request); - } else if (response.status_code >= 300) { - cause = SIP.C.REASON_PHRASE[response.status_code] || SIP.C.causes.CANCELED; - this.rejected(response, cause); - this.failed(response, cause); - this.terminated(response, cause); - } - return; - } - - switch (true) { - case /^100$/.test(response.status_code): - this.received_100 = true; - this.emit('progress', response); - break; - case /^1[0-9]{2}$/.test(response.status_code): - // Do nothing with 1xx responses without To tag. - if (!response.to_tag) { - this.logger.warn('1xx response received without to tag'); - break; - } - - // Create Early Dialog if 1XX comes with contact - if (response.hasHeader('contact')) { - // An error on dialog creation will fire 'failed' event - if (!this.createDialog(response, 'UAC', true)) { - break; - } - } - - this.status = C.STATUS_1XX_RECEIVED; - - if (response.hasHeader('require') && response.getHeader('require').indexOf('100rel') !== -1) { - - // Do nothing if this.dialog is already confirmed - if (this.dialog || !this.earlyDialogs[id]) { - break; - } - - if (this.earlyDialogs[id].pracked.indexOf(response.getHeader('rseq')) !== -1 || this.earlyDialogs[id].pracked[this.earlyDialogs[id].pracked.length - 1] >= response.getHeader('rseq') && this.earlyDialogs[id].pracked.length > 0) { - return; - } - // TODO: This may be broken. It may have to be on the early dialog - this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions); - if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) { - extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq')); - this.earlyDialogs[id].pracked.push(response.getHeader('rseq')); - this.earlyDialogs[id].sendRequest(this, SIP.C.PRACK, { - extraHeaders: extraHeaders - }); - this.emit('progress', response); - } else if (this.hasOffer) { - if (!this.createDialog(response, 'UAC')) { - break; - } - this.hasAnswer = true; - this.dialog.pracked.push(response.getHeader('rseq')); - - this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function onSuccess() { - extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq')); - - session.sendRequest(SIP.C.PRACK, { - extraHeaders: extraHeaders, - receiveResponse: function receiveResponse() {} - }); - session.status = C.STATUS_EARLY_MEDIA; - session.emit('progress', response); - }, function onFailure(e) { - session.logger.warn(e); - session.acceptAndTerminate(response, 488, 'Not Acceptable Here'); - session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - }); - } else { - var earlyDialog = this.earlyDialogs[id]; - var earlyMedia = earlyDialog.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerOptions); - - earlyDialog.pracked.push(response.getHeader('rseq')); - - earlyMedia.setDescription(response.body, session.sessionDescriptionHandlerOptions, session.modifers).then(earlyMedia.getDescription.bind(earlyMedia, session.sessionDescriptionHandlerOptions, session.modifiers)).then(function onSuccess(description) { - extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq')); - earlyDialog.sendRequest(session, SIP.C.PRACK, { - extraHeaders: extraHeaders, - body: description - }); - session.status = C.STATUS_EARLY_MEDIA; - session.emit('progress', response); - }).catch(function onFailure(e) { - if (e instanceof SIP.Exceptions.GetDescriptionError) { - earlyDialog.pracked.push(response.getHeader('rseq')); - if (session.status === C.STATUS_TERMINATED) { - return; - } - session.failed(null, SIP.C.causes.WEBRTC_ERROR); - session.terminated(null, SIP.C.causes.WEBRTC_ERROR); - } else { - earlyDialog.pracked.splice(earlyDialog.pracked.indexOf(response.getHeader('rseq')), 1); - // Could not set remote description - session.logger.warn('invalid description'); - session.logger.warn(e); - } - }); - } - } else { - this.emit('progress', response); - } - break; - case /^2[0-9]{2}$/.test(response.status_code): - var cseq = this.request.cseq + ' ' + this.request.method; - if (cseq !== response.getHeader('cseq')) { - break; - } - - if (this.status === C.STATUS_EARLY_MEDIA && this.dialog) { - this.status = C.STATUS_CONFIRMED; - options = {}; - if (this.renderbody) { - extraHeaders.push('Content-Type: ' + this.rendertype); - options.extraHeaders = extraHeaders; - options.body = this.renderbody; - } - this.emit("ack", response.transaction.sendACK(options)); - this.accepted(response); - break; - } - // Do nothing if this.dialog is already confirmed - if (this.dialog) { - break; - } - - // This is an invite without sdp - if (!this.hasOffer) { - if (this.earlyDialogs[id] && this.earlyDialogs[id].sessionDescriptionHandler) { - //REVISIT - this.hasOffer = true; - this.hasAnswer = true; - this.sessionDescriptionHandler = this.earlyDialogs[id].sessionDescriptionHandler; - if (!this.createDialog(response, 'UAC')) { - break; - } - this.status = C.STATUS_CONFIRMED; - this.emit("ack", response.transaction.sendACK()); - - this.accepted(response); - } else { - this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions); - - if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) { - this.acceptAndTerminate(response, 400, 'Missing session description'); - this.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - break; - } - if (!this.createDialog(response, 'UAC')) { - break; - } - this.hasOffer = true; - this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler, this.sessionDescriptionHandlerOptions, this.modifiers)).then(function onSuccess(description) { - //var localMedia; - if (session.isCanceled || session.status === C.STATUS_TERMINATED) { - return; - } - - session.status = C.STATUS_CONFIRMED; - session.hasAnswer = true; - - session.emit("ack", response.transaction.sendACK({ body: description })); - session.accepted(response); - }).catch(function onFailure(e) { - if (e instanceof SIP.Exceptions.GetDescriptionError) { - // TODO do something here - session.logger.warn("there was a problem"); - } else { - session.logger.warn('invalid description'); - session.logger.warn(e); - session.acceptAndTerminate(response, 488, 'Invalid session description'); - session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - } - }); - } - } else if (this.hasAnswer) { - if (this.renderbody) { - extraHeaders.push('Content-Type: ' + session.rendertype); - options.extraHeaders = extraHeaders; - options.body = this.renderbody; - } - this.emit("ack", response.transaction.sendACK(options)); - } else { - if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) { - this.acceptAndTerminate(response, 400, 'Missing session description'); - this.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - break; - } - if (!this.createDialog(response, 'UAC')) { - break; - } - this.hasAnswer = true; - this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function onSuccess() { - var options = {}; - session.status = C.STATUS_CONFIRMED; - if (session.renderbody) { - extraHeaders.push('Content-Type: ' + session.rendertype); - options.extraHeaders = extraHeaders; - options.body = session.renderbody; - } - session.emit("ack", response.transaction.sendACK(options)); - session.accepted(response); - }, function onFailure(e) { - session.logger.warn(e); - session.acceptAndTerminate(response, 488, 'Not Acceptable Here'); - session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION); - }); - } - break; - default: - cause = SIP.Utils.sipErrorCause(response.status_code); - this.rejected(response, cause); - this.failed(response, cause); - this.terminated(response, cause); - } - }, - - cancel: function cancel(options) { - options = options || {}; - - options.extraHeaders = (options.extraHeaders || []).slice(); - - // Check Session Status - if (this.status === C.STATUS_TERMINATED || this.status === C.STATUS_CONFIRMED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - this.logger.log('canceling RTCSession'); - - var cancel_reason = SIP.Utils.getCancelReason(options.status_code, options.reason_phrase); - - // Check Session Status - if (this.status === C.STATUS_NULL || this.status === C.STATUS_INVITE_SENT && !this.received_100) { - this.isCanceled = true; - this.cancelReason = cancel_reason; - } else if (this.status === C.STATUS_INVITE_SENT || this.status === C.STATUS_1XX_RECEIVED || this.status === C.STATUS_EARLY_MEDIA) { - this.request.cancel(cancel_reason, options.extraHeaders); - } - - return this.canceled(); - }, - - terminate: function terminate(options) { - if (this.status === C.STATUS_TERMINATED) { - return this; - } - - if (this.status === C.STATUS_WAITING_FOR_ACK || this.status === C.STATUS_CONFIRMED) { - this.bye(options); - } else { - this.cancel(options); - } - - return this; - }, - - receiveRequest: function receiveRequest(request) { - // ICC RECEIVE REQUEST - - // Reject CANCELs - if (request.method === SIP.C.CANCEL) { - // TODO; make this a switch when it gets added - } - - if (request.method === SIP.C.ACK && this.status === C.STATUS_WAITING_FOR_ACK) { - - SIP.Timers.clearTimeout(this.timers.ackTimer); - SIP.Timers.clearTimeout(this.timers.invite2xxTimer); - this.status = C.STATUS_CONFIRMED; - - this.accepted(); - } - - return Session.prototype.receiveRequest.apply(this, [request]); - }, - - onTransportError: function onTransportError() { - if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.CONNECTION_ERROR); - } - }, - - onRequestTimeout: function onRequestTimeout() { - if (this.status === C.STATUS_CONFIRMED) { - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } else if (this.status !== C.STATUS_TERMINATED) { - this.failed(null, SIP.C.causes.REQUEST_TIMEOUT); - this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT); - } - } - - }; - - SIP.InviteClientContext = InviteClientContext; - - ReferClientContext = function ReferClientContext(ua, applicant, target, options) { - this.options = options || {}; - this.extraHeaders = (this.options.extraHeaders || []).slice(); - - if (ua === undefined || applicant === undefined || target === undefined) { - throw new TypeError('Not enough arguments'); - } - - SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.REFER, applicant.remoteIdentity.uri.toString(), options]); - - this.applicant = applicant; - - var withReplaces = target instanceof SIP.InviteServerContext || target instanceof SIP.InviteClientContext; - if (withReplaces) { - // Attended Transfer - // All of these fields should be defined based on the check above - this.target = '"' + target.remoteIdentity.friendlyName + '" ' + '<' + target.dialog.remote_target.toString() + '?Replaces=' + target.dialog.id.call_id + '%3Bto-tag%3D' + target.dialog.id.remote_tag + '%3Bfrom-tag%3D' + target.dialog.id.local_tag + '>'; - } else { - // Blind Transfer - // Refer-To: - try { - this.target = SIP.Grammar.parse(target, 'Refer_To').uri || target; - } catch (e) { - this.logger.debug(".refer() cannot parse Refer_To from", target); - this.logger.debug("...falling through to normalizeTarget()"); - } - - // Check target validity - this.target = this.ua.normalizeTarget(this.target); - if (!this.target) { - throw new TypeError('Invalid target: ' + target); - } - } - - if (this.ua) { - this.extraHeaders.push('Referred-By: <' + this.ua.configuration.uri + '>'); - } - // TODO: Check that this is correct isc/icc - this.extraHeaders.push('Contact: ' + applicant.contact); - this.extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - this.extraHeaders.push('Refer-To: ' + this.target); - }; - - ReferClientContext.prototype = { - - refer: function refer(options) { - options = options || {}; - - var extraHeaders = (this.extraHeaders || []).slice(); - if (options.extraHeaders) { - extraHeaders.concat(options.extraHeaders); - } - - this.applicant.sendRequest(SIP.C.REFER, { - extraHeaders: this.extraHeaders, - receiveResponse: function (response) { - if (/^1[0-9]{2}$/.test(response.status_code)) { - this.emit('referRequestProgress', this); - } else if (/^2[0-9]{2}$/.test(response.status_code)) { - this.emit('referRequestAccepted', this); - } else if (/^[4-6][0-9]{2}$/.test(response.status_code)) { - this.emit('referRequestRejected', this); - } - if (options.receiveResponse) { - options.receiveResponse(response); - } - }.bind(this) - }); - return this; - }, - - receiveNotify: function receiveNotify(request) { - // If we can correctly handle this, then we need to send a 200 OK! - if (request.hasHeader('Content-Type') && request.getHeader('Content-Type').search(/^message\/sipfrag/) !== -1) { - var messageBody = SIP.Grammar.parse(request.body, 'sipfrag'); - if (messageBody === -1) { - request.reply(489, 'Bad Event'); - return; - } - switch (true) { - case /^1[0-9]{2}$/.test(messageBody.status_code): - this.emit('referProgress', this); - break; - case /^2[0-9]{2}$/.test(messageBody.status_code): - this.emit('referAccepted', this); - if (!this.options.activeAfterTransfer && this.applicant.terminate) { - this.applicant.terminate(); - } - break; - default: - this.emit('referRejected', this); - break; - } - request.reply(200); - this.emit('notify', request); - return; - } - request.reply(489, 'Bad Event'); - } - }; - - SIP.ReferClientContext = ReferClientContext; - - ReferServerContext = function ReferServerContext(ua, request) { - SIP.Utils.augment(this, SIP.ServerContext, [ua, request]); - - this.ua = ua; - - this.status = C.STATUS_INVITE_RECEIVED; - this.from_tag = request.from_tag; - this.id = request.call_id + this.from_tag; - this.request = request; - this.contact = this.ua.contact.toString(); - - this.logger = ua.getLogger('sip.referservercontext', this.id); - - // RFC 3515 2.4.1 - if (!this.request.hasHeader('refer-to')) { - this.logger.warn('Invalid REFER packet. A refer-to header is required. Rejecting refer.'); - this.reject(); - return; - } - - this.referTo = this.request.parseHeader('refer-to'); - - // TODO: Must set expiration timer and send 202 if there is no response by then - - this.referredSession = this.ua.findSession(request); - - // Needed to send the NOTIFY's - this.cseq = Math.floor(Math.random() * 10000); - this.call_id = this.request.call_id; - this.from_uri = this.request.to.uri; - this.from_tag = this.request.to.parameters.tag; - this.remote_target = this.request.headers.Contact[0].parsed.uri; - this.to_uri = this.request.from.uri; - this.to_tag = this.request.from_tag; - this.route_set = this.request.getHeaders('record-route'); - - this.receiveNonInviteResponse = function () {}; - - if (this.request.hasHeader('referred-by')) { - this.referredBy = this.request.getHeader('referred-by'); - } - - if (this.referTo.uri.hasHeader('replaces')) { - this.replaces = this.referTo.uri.getHeader('replaces'); - } - - this.status = C.STATUS_WAITING_FOR_ANSWER; - }; - - ReferServerContext.prototype = { - - progress: function progress() { - if (this.status !== C.STATUS_WAITING_FOR_ANSWER) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - this.request.reply(100); - }, - - reject: function reject(options) { - if (this.status === C.STATUS_TERMINATED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - this.logger.log('Rejecting refer'); - this.status = C.STATUS_TERMINATED; - SIP.ServerContext.prototype.reject.call(this, options); - this.emit('referRequestRejected', this); - }, - - accept: function accept(options, modifiers) { - options = options || {}; - - if (this.status === C.STATUS_WAITING_FOR_ANSWER) { - this.status = C.STATUS_ANSWERED; - } else { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - - this.request.reply(202, 'Accepted'); - this.emit('referRequestAccepted', this); - - if (options.followRefer) { - this.logger.log('Accepted refer, attempting to automatically follow it'); - - var target = this.referTo.uri; - if (!target.scheme.match("^sips?$")) { - this.logger.error('SIP.js can only automatically follow SIP refer target'); - this.reject(); - return; - } - - var inviteOptions = options.inviteOptions || {}; - var extraHeaders = (inviteOptions.extraHeaders || []).slice(); - if (this.replaces) { - // decodeURIComponent is a holdover from 2c086eb4. Not sure that it is actually necessary - extraHeaders.push('Replaces: ' + decodeURIComponent(this.replaces)); - } - - if (this.referredBy) { - extraHeaders.push('Referred-By: ' + this.referredBy); - } - - inviteOptions.extraHeaders = extraHeaders; - - target.clearHeaders(); - - this.targetSession = this.ua.invite(target, inviteOptions, modifiers); - - this.emit('referInviteSent', this); - - this.targetSession.once('progress', function () { - this.sendNotify('SIP/2.0 100 Trying'); - this.emit('referProgress', this); - if (this.referredSession) { - this.referredSession.emit('referProgress', this); - } - }.bind(this)); - this.targetSession.once('accepted', function () { - this.logger.log('Successfully followed the refer'); - this.sendNotify('SIP/2.0 200 OK'); - this.emit('referAccepted', this); - if (this.referredSession) { - this.referredSession.emit('referAccepted', this); - } - }.bind(this)); - - var referFailed = function referFailed(response) { - if (this.status === C.STATUS_TERMINATED) { - return; // No throw here because it is possible this gets called multiple times - } - this.logger.log('Refer was not successful. Resuming session'); - if (response && response.status_code === 429) { - this.logger.log('Alerting referrer that identity is required.'); - this.sendNotify('SIP/2.0 429 Provide Referrer Identity'); - return; - } - this.sendNotify('SIP/2.0 603 Declined'); - // Must change the status after sending the final Notify or it will not send due to check - this.status = C.STATUS_TERMINATED; - this.emit('referRejected', this); - if (this.referredSession) { - this.referredSession.emit('referRejected'); - } - }; - - this.targetSession.once('rejected', referFailed.bind(this)); - this.targetSession.once('failed', referFailed.bind(this)); - } else { - this.logger.log('Accepted refer, but did not automatically follow it'); - this.sendNotify('SIP/2.0 200 OK'); - this.emit('referAccepted', this); - if (this.referredSession) { - this.referredSession.emit('referAccepted', this); - } - } - }, - - sendNotify: function sendNotify(body) { - if (this.status !== C.STATUS_ANSWERED) { - throw new SIP.Exceptions.InvalidStateError(this.status); - } - if (SIP.Grammar.parse(body, 'sipfrag') === -1) { - throw new Error('sipfrag body is required to send notify for refer'); - } - - var request = new SIP.OutgoingRequest(SIP.C.NOTIFY, this.remote_target, this.ua, { - cseq: this.cseq += 1, // randomly generated then incremented on each additional notify - call_id: this.call_id, // refer call_id - from_uri: this.from_uri, - from_tag: this.from_tag, - to_uri: this.to_uri, - to_tag: this.to_tag, - route_set: this.route_set - }, ['Event: refer', 'Subscription-State: terminated', 'Content-Type: message/sipfrag'], body); - - new SIP.RequestSender({ - request: request, - onRequestTimeout: function onRequestTimeout() { - return; - }, - onTransportError: function onTransportError() { - return; - }, - receiveResponse: function receiveResponse() { - return; - } - }, this.ua).send(); - } - }; - - SIP.ReferServerContext = ReferServerContext; -}; - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview DTMF - */ - -/** - * @class DTMF - * @param {SIP.Session} session - */ - -module.exports = function (SIP) { - - var _DTMF, - C = { - MIN_DURATION: 70, - MAX_DURATION: 6000, - DEFAULT_DURATION: 100, - MIN_INTER_TONE_GAP: 50, - DEFAULT_INTER_TONE_GAP: 500 - }; - - _DTMF = function DTMF(session, tone, options) { - var duration, interToneGap; - - if (tone === undefined) { - throw new TypeError('Not enough arguments'); - } - - this.logger = session.ua.getLogger('sip.invitecontext.dtmf', session.id); - this.owner = session; - this.direction = null; - - options = options || {}; - duration = options.duration || null; - interToneGap = options.interToneGap || null; - - // Check tone type - if (typeof tone === 'string') { - tone = tone.toUpperCase(); - } else if (typeof tone === 'number') { - tone = tone.toString(); - } else { - throw new TypeError('Invalid tone: ' + tone); - } - - // Check tone value - if (!tone.match(/^[0-9A-D#*]$/)) { - throw new TypeError('Invalid tone: ' + tone); - } else { - this.tone = tone; - } - - // Check duration - if (duration && !SIP.Utils.isDecimal(duration)) { - throw new TypeError('Invalid tone duration: ' + duration); - } else if (!duration) { - duration = _DTMF.C.DEFAULT_DURATION; - } else if (duration < _DTMF.C.MIN_DURATION) { - this.logger.warn('"duration" value is lower than the minimum allowed, setting it to ' + _DTMF.C.MIN_DURATION + ' milliseconds'); - duration = _DTMF.C.MIN_DURATION; - } else if (duration > _DTMF.C.MAX_DURATION) { - this.logger.warn('"duration" value is greater than the maximum allowed, setting it to ' + _DTMF.C.MAX_DURATION + ' milliseconds'); - duration = _DTMF.C.MAX_DURATION; - } else { - duration = Math.abs(duration); - } - this.duration = duration; - - // Check interToneGap - if (interToneGap && !SIP.Utils.isDecimal(interToneGap)) { - throw new TypeError('Invalid interToneGap: ' + interToneGap); - } else if (!interToneGap) { - interToneGap = _DTMF.C.DEFAULT_INTER_TONE_GAP; - } else if (interToneGap < _DTMF.C.MIN_INTER_TONE_GAP) { - this.logger.warn('"interToneGap" value is lower than the minimum allowed, setting it to ' + _DTMF.C.MIN_INTER_TONE_GAP + ' milliseconds'); - interToneGap = _DTMF.C.MIN_INTER_TONE_GAP; - } else { - interToneGap = Math.abs(interToneGap); - } - this.interToneGap = interToneGap; - }; - _DTMF.prototype = Object.create(SIP.EventEmitter.prototype); - - _DTMF.prototype.send = function (options) { - var extraHeaders, - body = {}; - - this.direction = 'outgoing'; - - // Check RTCSession Status - if (this.owner.status !== SIP.Session.C.STATUS_CONFIRMED && this.owner.status !== SIP.Session.C.STATUS_WAITING_FOR_ACK) { - throw new SIP.Exceptions.InvalidStateError(this.owner.status); - } - - // Get DTMF options - options = options || {}; - extraHeaders = options.extraHeaders ? options.extraHeaders.slice() : []; - - body.contentType = 'application/dtmf-relay'; - - body.body = "Signal= " + this.tone + "\r\n"; - body.body += "Duration= " + this.duration; - - this.request = this.owner.dialog.sendRequest(this, SIP.C.INFO, { - extraHeaders: extraHeaders, - body: body - }); - - this.owner.emit('dtmf', this.request, this); - }; - - /** - * @private - */ - _DTMF.prototype.receiveResponse = function (response) { - var cause; - - switch (true) { - case /^1[0-9]{2}$/.test(response.status_code): - // Ignore provisional responses. - break; - - case /^2[0-9]{2}$/.test(response.status_code): - this.emit('succeeded', { - originator: 'remote', - response: response - }); - break; - - default: - cause = SIP.Utils.sipErrorCause(response.status_code); - this.emit('failed', response, cause); - break; - } - }; - - /** - * @private - */ - _DTMF.prototype.onRequestTimeout = function () { - this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT); - this.owner.onRequestTimeout(); - }; - - /** - * @private - */ - _DTMF.prototype.onTransportError = function () { - this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR); - this.owner.onTransportError(); - }; - - /** - * @private - */ - _DTMF.prototype.onDialogError = function (response) { - this.emit('failed', response, SIP.C.causes.DIALOG_ERROR); - this.owner.onDialogError(response); - }; - - /** - * @private - */ - _DTMF.prototype.init_incoming = function (request) { - this.direction = 'incoming'; - this.request = request; - - request.reply(200); - - if (!this.tone || !this.duration) { - this.logger.warn('invalid INFO DTMF received, discarded'); - } else { - this.owner.emit('dtmf', request, this); - } - }; - - _DTMF.C = C; - return _DTMF; -}; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * @fileoverview SIP Subscriber (SIP-Specific Event Notifications RFC6665) - */ - -/** - * @augments SIP - * @class Class creating a SIP Subscription. - */ - -module.exports = function (SIP) { - SIP.Subscription = function (ua, target, event, options) { - options = Object.create(options || Object.prototype); - this.extraHeaders = options.extraHeaders = (options.extraHeaders || []).slice(); - - this.id = null; - this.state = 'init'; - - if (!event) { - throw new TypeError('Event necessary to create a subscription.'); - } else { - //TODO: check for valid events here probably make a list in SIP.C; or leave it up to app to check? - //The check may need to/should probably occur on the other side, - this.event = event; - } - - if (typeof options.expires !== 'number') { - ua.logger.warn('expires must be a number. Using default of 3600.'); - this.expires = 3600; - } else { - this.expires = options.expires; - } - this.requestedExpires = this.expires; - - options.extraHeaders.push('Event: ' + this.event); - options.extraHeaders.push('Expires: ' + this.expires); - - if (options.body) { - this.body = options.body; - } - - this.contact = ua.contact.toString(); - - options.extraHeaders.push('Contact: ' + this.contact); - options.extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.SUBSCRIBE, target, options]); - - this.logger = ua.getLogger('sip.subscription'); - - this.dialog = null; - this.timers = { N: null, sub_duration: null }; - this.errorCodes = [404, 405, 410, 416, 480, 481, 482, 483, 484, 485, 489, 501, 604]; - }; - - SIP.Subscription.prototype = { - subscribe: function subscribe() { - var sub = this; - - //these states point to an existing subscription, no subscribe is necessary - if (this.state === 'active') { - this.refresh(); - return this; - } else if (this.state === 'notify_wait') { - return this; - } - - SIP.Timers.clearTimeout(this.timers.sub_duration); - SIP.Timers.clearTimeout(this.timers.N); - this.timers.N = SIP.Timers.setTimeout(sub.timer_fire.bind(sub), SIP.Timers.TIMER_N); - - this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event] = this; - - this.send(); - - this.state = 'notify_wait'; - - return this; - }, - - refresh: function refresh() { - if (this.state === 'terminated' || this.state === 'pending' || this.state === 'notify_wait') { - return; - } - - this.dialog.sendRequest(this, SIP.C.SUBSCRIBE, { - extraHeaders: this.extraHeaders, - body: this.body - }); - }, - - receiveResponse: function receiveResponse(response) { - var expires, - sub = this, - cause = SIP.Utils.getReasonPhrase(response.status_code); - - if (this.state === 'notify_wait' && response.status_code >= 300 || this.state !== 'notify_wait' && this.errorCodes.indexOf(response.status_code) !== -1) { - this.failed(response, null); - } else if (/^2[0-9]{2}$/.test(response.status_code)) { - this.emit('accepted', response, cause); - //As we don't support RFC 5839 or other extensions where the NOTIFY is optional, timer N will not be cleared - //SIP.Timers.clearTimeout(this.timers.N); - - expires = response.getHeader('Expires'); - - if (expires && expires <= this.requestedExpires) { - // Preserve new expires value for subsequent requests - this.expires = expires; - this.timers.sub_duration = SIP.Timers.setTimeout(sub.refresh.bind(sub), expires * 900); - } else { - if (!expires) { - this.logger.warn('Expires header missing in a 200-class response to SUBSCRIBE'); - this.failed(response, SIP.C.EXPIRES_HEADER_MISSING); - } else { - this.logger.warn('Expires header in a 200-class response to SUBSCRIBE with a higher value than the one in the request'); - this.failed(response, SIP.C.INVALID_EXPIRES_HEADER); - } - } - } else if (response.statusCode > 300) { - this.emit('failed', response, cause); - this.emit('rejected', response, cause); - } - }, - - unsubscribe: function unsubscribe() { - var extraHeaders = [], - sub = this; - - this.state = 'terminated'; - - extraHeaders.push('Event: ' + this.event); - extraHeaders.push('Expires: 0'); - - extraHeaders.push('Contact: ' + this.contact); - extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString()); - - //makes sure expires isn't set, and other typical resubscribe behavior - this.receiveResponse = function () {}; - - this.dialog.sendRequest(this, this.method, { - extraHeaders: extraHeaders, - body: this.body - }); - - SIP.Timers.clearTimeout(this.timers.sub_duration); - SIP.Timers.clearTimeout(this.timers.N); - this.timers.N = SIP.Timers.setTimeout(sub.timer_fire.bind(sub), SIP.Timers.TIMER_N); - }, - - /** - * @private - */ - timer_fire: function timer_fire() { - if (this.state === 'terminated') { - this.terminateDialog(); - SIP.Timers.clearTimeout(this.timers.N); - SIP.Timers.clearTimeout(this.timers.sub_duration); - - delete this.ua.subscriptions[this.id]; - } else if (this.state === 'notify_wait' || this.state === 'pending') { - this.close(); - } else { - this.refresh(); - } - }, - - /** - * @private - */ - close: function close() { - if (this.state === 'notify_wait') { - this.state = 'terminated'; - SIP.Timers.clearTimeout(this.timers.N); - SIP.Timers.clearTimeout(this.timers.sub_duration); - this.receiveResponse = function () {}; - - delete this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event]; - } else if (this.state !== 'terminated') { - this.unsubscribe(); - } - }, - - /** - * @private - */ - createConfirmedDialog: function createConfirmedDialog(message, type) { - var dialog; - - this.terminateDialog(); - dialog = new SIP.Dialog(this, message, type); - dialog.invite_seqnum = this.request.cseq; - dialog.local_seqnum = this.request.cseq; - - if (!dialog.error) { - this.dialog = dialog; - return true; - } - // Dialog not created due to an error - else { - return false; - } - }, - - /** - * @private - */ - terminateDialog: function terminateDialog() { - if (this.dialog) { - delete this.ua.subscriptions[this.id]; - this.dialog.terminate(); - delete this.dialog; - } - }, - - /** - * @private - */ - receiveRequest: function receiveRequest(request) { - var sub_state, - sub = this; - - function setExpiresTimeout() { - if (sub_state.expires) { - SIP.Timers.clearTimeout(sub.timers.sub_duration); - sub_state.expires = Math.min(sub.expires, Math.max(sub_state.expires, 0)); - sub.timers.sub_duration = SIP.Timers.setTimeout(sub.refresh.bind(sub), sub_state.expires * 900); - } - } - - if (!this.matchEvent(request)) { - //checks event and subscription_state headers - request.reply(489); - return; - } - - if (!this.dialog) { - if (this.createConfirmedDialog(request, 'UAS')) { - this.id = this.dialog.id.toString(); - delete this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event]; - this.ua.subscriptions[this.id] = this; - // UPDATE ROUTE SET TO BE BACKWARDS COMPATIBLE? - } - } - - sub_state = request.parseHeader('Subscription-State'); - - request.reply(200, SIP.C.REASON_200); - - SIP.Timers.clearTimeout(this.timers.N); - - this.emit('notify', { request: request }); - - // if we've set state to terminated, no further processing should take place - // and we are only interested in cleaning up after the appropriate NOTIFY - if (this.state === 'terminated') { - if (sub_state.state === 'terminated') { - this.terminateDialog(); - SIP.Timers.clearTimeout(this.timers.N); - SIP.Timers.clearTimeout(this.timers.sub_duration); - - delete this.ua.subscriptions[this.id]; - } - return; - } - - switch (sub_state.state) { - case 'active': - this.state = 'active'; - setExpiresTimeout(); - break; - case 'pending': - if (this.state === 'notify_wait') { - setExpiresTimeout(); - } - this.state = 'pending'; - break; - case 'terminated': - SIP.Timers.clearTimeout(this.timers.sub_duration); - if (sub_state.reason) { - this.logger.log('terminating subscription with reason ' + sub_state.reason); - switch (sub_state.reason) { - case 'deactivated': - case 'timeout': - this.subscribe(); - return; - case 'probation': - case 'giveup': - if (sub_state.params && sub_state.params['retry-after']) { - this.timers.sub_duration = SIP.Timers.setTimeout(sub.subscribe.bind(sub), sub_state.params['retry-after']); - } else { - this.subscribe(); - } - return; - case 'rejected': - case 'noresource': - case 'invariant': - break; - } - } - this.close(); - break; - } - }, - - failed: function failed(response, cause) { - this.close(); - this.emit('failed', response, cause); - this.emit('rejected', response, cause); - return this; - }, - - onDialogError: function onDialogError(response) { - this.failed(response, SIP.C.causes.DIALOG_ERROR); - }, - - /** - * @private - */ - matchEvent: function matchEvent(request) { - var event; - - // Check mandatory header Event - if (!request.hasHeader('Event')) { - this.logger.warn('missing Event header'); - return false; - } - // Check mandatory header Subscription-State - if (!request.hasHeader('Subscription-State')) { - this.logger.warn('missing Subscription-State header'); - return false; - } - - // Check whether the event in NOTIFY matches the event in SUBSCRIBE - event = request.parseHeader('event').event; - - if (this.event !== event) { - this.logger.warn('event match failed'); - request.reply(481, 'Event Match Failed'); - return false; - } else { - return true; - } - } - }; -}; - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -/** - * @augments SIP - * @class Class creating a SIP User Agent. - * @param {function returning SIP.sessionDescriptionHandler} [configuration.sessionDescriptionHandlerFactory] - * A function will be invoked by each of the UA's Sessions to build the sessionDescriptionHandler for that Session. - * If no (or a falsy) value is provided, each Session will use a default (WebRTC) sessionDescriptionHandler. - * - * @param {Object} [configuration.media] gets passed to SIP.sessionDescriptionHandler.getDescription as mediaHint - */ - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -module.exports = function (SIP, environment) { - var UA, - C = { - // UA status codes - STATUS_INIT: 0, - STATUS_STARTING: 1, - STATUS_READY: 2, - STATUS_USER_CLOSED: 3, - STATUS_NOT_READY: 4, - - // UA error codes - CONFIGURATION_ERROR: 1, - NETWORK_ERROR: 2, - - ALLOWED_METHODS: ['ACK', 'CANCEL', 'INVITE', 'MESSAGE', 'BYE', 'OPTIONS', 'INFO', 'NOTIFY', 'REFER'], - - ACCEPTED_BODY_TYPES: ['application/sdp', 'application/dtmf-relay'], - - MAX_FORWARDS: 70, - TAG_LENGTH: 10 - }; - - UA = function UA(configuration) { - var self = this; - - // Helper function for forwarding events - function selfEmit(type) { - //registrationFailed handler is invoked with two arguments. Allow event handlers to be invoked with a variable no. of arguments - return self.emit.bind(self, type); - } - - // Set Accepted Body Types - C.ACCEPTED_BODY_TYPES = C.ACCEPTED_BODY_TYPES.toString(); - - this.log = new SIP.LoggerFactory(); - this.logger = this.getLogger('sip.ua'); - - this.cache = { - credentials: {} - }; - - this.configuration = {}; - this.dialogs = {}; - - //User actions outside any session/dialog (MESSAGE) - this.applicants = {}; - - this.data = {}; - this.sessions = {}; - this.subscriptions = {}; - this.earlySubscriptions = {}; - this.transport = null; - this.contact = null; - this.status = C.STATUS_INIT; - this.error = null; - this.transactions = { - nist: {}, - nict: {}, - ist: {}, - ict: {} - }; - - this.transportRecoverAttempts = 0; - this.transportRecoveryTimer = null; - - Object.defineProperties(this, { - transactionsCount: { - get: function get() { - var type, - transactions = ['nist', 'nict', 'ist', 'ict'], - count = 0; - - for (type in transactions) { - count += Object.keys(this.transactions[transactions[type]]).length; - } - - return count; - } - }, - - nictTransactionsCount: { - get: function get() { - return Object.keys(this.transactions['nict']).length; - } - }, - - nistTransactionsCount: { - get: function get() { - return Object.keys(this.transactions['nist']).length; - } - }, - - ictTransactionsCount: { - get: function get() { - return Object.keys(this.transactions['ict']).length; - } - }, - - istTransactionsCount: { - get: function get() { - return Object.keys(this.transactions['ist']).length; - } - } - }); - - /** - * Load configuration - * - * @throws {SIP.Exceptions.ConfigurationError} - * @throws {TypeError} - */ - - if (configuration === undefined) { - configuration = {}; - } else if (typeof configuration === 'string' || configuration instanceof String) { - configuration = { - uri: configuration - }; - } - - // Apply log configuration if present - if (configuration.log) { - if (configuration.log.hasOwnProperty('builtinEnabled')) { - this.log.builtinEnabled = configuration.log.builtinEnabled; - } - - if (configuration.log.hasOwnProperty('level')) { - this.log.level = configuration.log.level; - } - - if (configuration.log.hasOwnProperty('connector')) { - this.log.connector = configuration.log.connector; - } - } - - try { - this.loadConfig(configuration); - } catch (e) { - this.status = C.STATUS_NOT_READY; - this.error = C.CONFIGURATION_ERROR; - throw e; - } - - // Initialize registerContext - this.registerContext = new SIP.RegisterContext(this); - this.registerContext.on('failed', selfEmit('registrationFailed')); - this.registerContext.on('registered', selfEmit('registered')); - this.registerContext.on('unregistered', selfEmit('unregistered')); - - if (this.configuration.autostart) { - this.start(); - } - }; - UA.prototype = Object.create(SIP.EventEmitter.prototype); - - //================= - // High Level API - //================= - - UA.prototype.register = function (options) { - this.configuration.register = true; - this.registerContext.register(options); - - return this; - }; - - /** - * Unregister. - * - * @param {Boolean} [all] unregister all user bindings. - * - */ - UA.prototype.unregister = function (options) { - this.configuration.register = false; - - var context = this.registerContext; - this.afterConnected(context.unregister.bind(context, options)); - - return this; - }; - - UA.prototype.isRegistered = function () { - return this.registerContext.registered; - }; - - /** - * Connection state. - * @param {Boolean} - */ - UA.prototype.isConnected = function () { - return this.transport ? this.transport.connected : false; - }; - - UA.prototype.afterConnected = function afterConnected(callback) { - if (this.isConnected()) { - callback(); - } else { - this.once('connected', callback); - } - }; - - /** - * Returns a promise which resolves once the UA is connected. - */ - UA.prototype.waitForConnected = function () { - return new SIP.Utils.Promise(function (resolve) { - this.afterConnected(resolve); - }.bind(this)); - }; - - /** - * Make an outgoing call. - * - * @param {String} target - * @param {Object} views - * @param {Object} [options.media] gets passed to SIP.sessionDescriptionHandler.getDescription as mediaHint - * - * @throws {TypeError} - * - */ - UA.prototype.invite = function (target, options, modifiers) { - var context = new SIP.InviteClientContext(this, target, options, modifiers); - - // Delay sending actual invite until the next 'tick' if we are already - // connected, so that API consumers can register to events fired by the - // the session. - this.waitForConnected().then(function () { - context.invite(); - this.emit('inviteSent', context); - }.bind(this)); - return context; - }; - - UA.prototype.subscribe = function (target, event, options) { - var sub = new SIP.Subscription(this, target, event, options); - - this.afterConnected(sub.subscribe.bind(sub)); - return sub; - }; - - /** - * Send a message. - * - * @param {String} target - * @param {String} body - * @param {Object} [options] - * - * @throws {TypeError} - * - */ - UA.prototype.message = function (target, body, options) { - if (body === undefined) { - throw new TypeError('Not enough arguments'); - } - - // There is no Message module, so it is okay that the UA handles defaults here. - options = Object.create(options || Object.prototype); - options.contentType || (options.contentType = 'text/plain'); - options.body = body; - - return this.request(SIP.C.MESSAGE, target, options); - }; - - UA.prototype.request = function (method, target, options) { - var req = new SIP.ClientContext(this, method, target, options); - - this.afterConnected(req.send.bind(req)); - return req; - }; - - /** - * Gracefully close. - * - */ - UA.prototype.stop = function () { - var session, - subscription, - applicant, - ua = this; - - function transactionsListener() { - if (ua.nistTransactionsCount === 0 && ua.nictTransactionsCount === 0) { - ua.removeListener('transactionDestroyed', transactionsListener); - ua.transport.disconnect(); - } - } - - this.logger.log('user requested closure...'); - - if (this.status === C.STATUS_USER_CLOSED) { - this.logger.warn('UA already closed'); - return this; - } - - // Clear transportRecoveryTimer - SIP.Timers.clearTimeout(this.transportRecoveryTimer); - - // Close registerContext - this.logger.log('closing registerContext'); - this.registerContext.close(); - - // Run _terminate_ on every Session - for (session in this.sessions) { - this.logger.log('closing session ' + session); - this.sessions[session].terminate(); - } - - //Run _close_ on every confirmed Subscription - for (subscription in this.subscriptions) { - this.logger.log('unsubscribing from subscription ' + subscription); - this.subscriptions[subscription].close(); - } - - //Run _close_ on every early Subscription - for (subscription in this.earlySubscriptions) { - this.logger.log('unsubscribing from early subscription ' + subscription); - this.earlySubscriptions[subscription].close(); - } - - // Run _close_ on every applicant - for (applicant in this.applicants) { - this.applicants[applicant].close(); - } - - this.status = C.STATUS_USER_CLOSED; - - /* - * If the remaining transactions are all INVITE transactions, there is no need to - * wait anymore because every session has already been closed by this method. - * - locally originated sessions where terminated (CANCEL or BYE) - * - remotely originated sessions where rejected (4XX) or terminated (BYE) - * Remaining INVITE transactions belong tho sessions that where answered. This are in - * 'accepted' state due to timers 'L' and 'M' defined in [RFC 6026] - */ - if (this.nistTransactionsCount === 0 && this.nictTransactionsCount === 0) { - this.transport.disconnect(); - } else { - this.on('transactionDestroyed', transactionsListener); - } - - if (typeof environment.removeEventListener === 'function') { - // Google Chrome Packaged Apps don't allow 'unload' listeners: - // unload is not available in packaged apps - if (!(global.chrome && global.chrome.app && global.chrome.app.runtime)) { - environment.removeEventListener('unload', this.environListener); - } - } - - return this; - }; - - /** - * Connect to the WS server if status = STATUS_INIT. - * Resume UA after being closed. - * - */ - UA.prototype.start = function () { - var server; - - this.logger.log('user requested startup...'); - if (this.status === C.STATUS_INIT) { - server = this.getNextWsServer(); - this.status = C.STATUS_STARTING; - new SIP.Transport(this, server); - } else if (this.status === C.STATUS_USER_CLOSED) { - this.logger.log('resuming'); - this.status = C.STATUS_READY; - this.transport.connect(); - } else if (this.status === C.STATUS_STARTING) { - this.logger.log('UA is in STARTING status, not opening new connection'); - } else if (this.status === C.STATUS_READY) { - this.logger.log('UA is in READY status, not resuming'); - } else { - this.logger.error('Connection is down. Auto-Recovery system is trying to connect'); - } - - if (this.configuration.autostop && typeof environment.addEventListener === 'function') { - // Google Chrome Packaged Apps don't allow 'unload' listeners: - // unload is not available in packaged apps - if (!(global.chrome && global.chrome.app && global.chrome.app.runtime)) { - this.environListener = this.stop.bind(this); - environment.addEventListener('unload', this.environListener); - } - } - - return this; - }; - - /** - * Normalize a string into a valid SIP request URI - * - * @param {String} target - * - * @returns {SIP.URI|undefined} - */ - UA.prototype.normalizeTarget = function (target) { - return SIP.Utils.normalizeTarget(target, this.configuration.hostportParams); - }; - - //=============================== - // Private (For internal use) - //=============================== - - UA.prototype.saveCredentials = function (credentials) { - this.cache.credentials[credentials.realm] = this.cache.credentials[credentials.realm] || {}; - this.cache.credentials[credentials.realm][credentials.uri] = credentials; - - return this; - }; - - UA.prototype.getCredentials = function (request) { - var realm, credentials; - - realm = request.ruri.host; - - if (this.cache.credentials[realm] && this.cache.credentials[realm][request.ruri]) { - credentials = this.cache.credentials[realm][request.ruri]; - credentials.method = request.method; - } - - return credentials; - }; - - UA.prototype.getLogger = function (category, label) { - return this.log.getLogger(category, label); - }; - - //============================== - // Event Handlers - //============================== - - /** - * Transport Close event - * @private - * @event - * @param {SIP.Transport} transport. - */ - UA.prototype.onTransportClosed = function (transport) { - // Run _onTransportError_ callback on every client transaction using _transport_ - var type, - idx, - length, - client_transactions = ['nict', 'ict', 'nist', 'ist']; - - transport.server.status = SIP.Transport.C.STATUS_DISCONNECTED; - this.logger.log('connection state set to ' + SIP.Transport.C.STATUS_DISCONNECTED); - - length = client_transactions.length; - for (type = 0; type < length; type++) { - for (idx in this.transactions[client_transactions[type]]) { - this.transactions[client_transactions[type]][idx].onTransportError(); - } - } - - // Close sessions if GRUU is not being used - if (!this.contact.pub_gruu) { - this.closeSessionsOnTransportError(); - } - }; - - /** - * Unrecoverable transport event. - * Connection reattempt logic has been done and didn't success. - * @private - * @event - * @param {SIP.Transport} transport. - */ - UA.prototype.onTransportError = function (transport) { - var server; - - this.logger.log('transport ' + transport.server.ws_uri + ' failed | connection state set to ' + SIP.Transport.C.STATUS_ERROR); - - // Close sessions. - //Mark this transport as 'down' - transport.server.status = SIP.Transport.C.STATUS_ERROR; - - this.emit('disconnected', { - transport: transport - }); - - // try the next transport if the UA isn't closed - if (this.status === C.STATUS_USER_CLOSED) { - return; - } - - server = this.getNextWsServer(); - - if (server) { - new SIP.Transport(this, server); - } else { - this.closeSessionsOnTransportError(); - if (!this.error || this.error !== C.NETWORK_ERROR) { - this.status = C.STATUS_NOT_READY; - this.error = C.NETWORK_ERROR; - } - // Transport Recovery process - this.recoverTransport(); - } - }; - - /** - * Transport connection event. - * @private - * @event - * @param {SIP.Transport} transport. - */ - UA.prototype.onTransportConnected = function (transport) { - this.transport = transport; - - // Reset transport recovery counter - this.transportRecoverAttempts = 0; - - transport.server.status = SIP.Transport.C.STATUS_READY; - this.logger.log('connection state set to ' + SIP.Transport.C.STATUS_READY); - - if (this.status === C.STATUS_USER_CLOSED) { - return; - } - - this.status = C.STATUS_READY; - this.error = null; - - if (this.configuration.register) { - this.configuration.authenticationFactory.initialize().then(function () { - this.registerContext.onTransportConnected(); - }.bind(this)); - } - - this.emit('connected', { - transport: transport - }); - }; - - /** - * Transport connecting event - * @private - * @param {SIP.Transport} transport. - * #param {Integer} attempts. - */ - UA.prototype.onTransportConnecting = function (transport, attempts) { - this.emit('connecting', { - transport: transport, - attempts: attempts - }); - }; - - /** - * new Transaction - * @private - * @param {SIP.Transaction} transaction. - */ - UA.prototype.newTransaction = function (transaction) { - this.transactions[transaction.type][transaction.id] = transaction; - this.emit('newTransaction', { transaction: transaction }); - }; - - /** - * destroy Transaction - * @private - * @param {SIP.Transaction} transaction. - */ - UA.prototype.destroyTransaction = function (transaction) { - delete this.transactions[transaction.type][transaction.id]; - this.emit('transactionDestroyed', { - transaction: transaction - }); - }; - - //========================= - // receiveRequest - //========================= - - /** - * Request reception - * @private - * @param {SIP.IncomingRequest} request. - */ - UA.prototype.receiveRequest = function (request) { - var dialog, - session, - message, - earlySubscription, - method = request.method, - replaces, - replacedDialog, - self = this; - - function ruriMatches(uri) { - return uri && uri.user === request.ruri.user; - } - - // Check that request URI points to us - if (!(ruriMatches(this.configuration.uri) || ruriMatches(this.contact.uri) || ruriMatches(this.contact.pub_gruu) || ruriMatches(this.contact.temp_gruu))) { - this.logger.warn('Request-URI does not point to us'); - if (request.method !== SIP.C.ACK) { - request.reply_sl(404); - } - return; - } - - // Check request URI scheme - if (request.ruri.scheme === SIP.C.SIPS) { - request.reply_sl(416); - return; - } - - // Check transaction - if (SIP.Transactions.checkTransaction(this, request)) { - return; - } - - /* RFC3261 12.2.2 - * Requests that do not change in any way the state of a dialog may be - * received within a dialog (for example, an OPTIONS request). - * They are processed as if they had been received outside the dialog. - */ - if (method === SIP.C.OPTIONS) { - new SIP.Transactions.NonInviteServerTransaction(request, this); - request.reply(200, null, ['Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString(), 'Accept: ' + C.ACCEPTED_BODY_TYPES]); - } else if (method === SIP.C.MESSAGE) { - message = new SIP.ServerContext(this, request); - message.body = request.body; - message.content_type = request.getHeader('Content-Type') || 'text/plain'; - - request.reply(200, null); - this.emit('message', message); - } else if (method !== SIP.C.INVITE && method !== SIP.C.ACK) { - // Let those methods pass through to normal processing for now. - new SIP.ServerContext(this, request); - } - - // Initial Request - if (!request.to_tag) { - switch (method) { - case SIP.C.INVITE: - replaces = this.configuration.replaces !== SIP.C.supported.UNSUPPORTED && request.parseHeader('replaces'); - - if (replaces) { - replacedDialog = this.dialogs[replaces.call_id + replaces.replaces_to_tag + replaces.replaces_from_tag]; - - if (!replacedDialog) { - //Replaced header without a matching dialog, reject - request.reply_sl(481, null); - return; - } else if (replacedDialog.owner.status === SIP.Session.C.STATUS_TERMINATED) { - request.reply_sl(603, null); - return; - } else if (replacedDialog.state === SIP.Dialog.C.STATUS_CONFIRMED && replaces.early_only) { - request.reply_sl(486, null); - return; - } - } - - session = new SIP.InviteServerContext(this, request); - session.replacee = replacedDialog && replacedDialog.owner; - self.emit('invite', session); - break; - case SIP.C.BYE: - // Out of dialog BYE received - request.reply(481); - break; - case SIP.C.CANCEL: - session = this.findSession(request); - if (session) { - session.receiveRequest(request); - } else { - this.logger.warn('received CANCEL request for a non existent session'); - } - break; - case SIP.C.ACK: - /* Absorb it. - * ACK request without a corresponding Invite Transaction - * and without To tag. - */ - break; - case SIP.C.NOTIFY: - if (this.configuration.allowLegacyNotifications && this.listeners('notify').length > 0) { - request.reply(200, null); - self.emit('notify', { request: request }); - } else { - request.reply(481, 'Subscription does not exist'); - } - break; - case SIP.C.REFER: - this.logger.log('Received an out of dialog refer'); - if (this.configuration.allowOutOfDialogRefers) { - this.logger.log('Allow out of dialog refers is enabled on the UA'); - var referContext = new SIP.ReferServerContext(this, request); - var hasReferListener = this.listeners('outOfDialogReferRequested').length; - if (hasReferListener) { - this.emit('outOfDialogReferRequested', referContext); - } else { - this.logger.log('No outOfDialogReferRequest listeners, automatically accepting and following the out of dialog refer'); - referContext.accept({ followRefer: true }); - } - break; - } - request.reply(405); - break; - default: - request.reply(405); - break; - } - } - // In-dialog request - else { - dialog = this.findDialog(request); - - if (dialog) { - if (method === SIP.C.INVITE) { - new SIP.Transactions.InviteServerTransaction(request, this); - } - dialog.receiveRequest(request); - } else if (method === SIP.C.NOTIFY) { - session = this.findSession(request); - earlySubscription = this.findEarlySubscription(request); - if (session) { - session.receiveRequest(request); - } else if (earlySubscription) { - earlySubscription.receiveRequest(request); - } else { - this.logger.warn('received NOTIFY request for a non existent session or subscription'); - request.reply(481, 'Subscription does not exist'); - } - } - /* RFC3261 12.2.2 - * Request with to tag, but no matching dialog found. - * Exception: ACK for an Invite request for which a dialog has not - * been created. - */ - else { - if (method !== SIP.C.ACK) { - request.reply(481); - } - } - } - }; - - //================= - // Utils - //================= - - /** - * Get the session to which the request belongs to, if any. - * @private - * @param {SIP.IncomingRequest} request. - * @returns {SIP.OutgoingSession|SIP.IncomingSession|null} - */ - UA.prototype.findSession = function (request) { - return this.sessions[request.call_id + request.from_tag] || this.sessions[request.call_id + request.to_tag] || null; - }; - - /** - * Get the dialog to which the request belongs to, if any. - * @private - * @param {SIP.IncomingRequest} - * @returns {SIP.Dialog|null} - */ - UA.prototype.findDialog = function (request) { - return this.dialogs[request.call_id + request.from_tag + request.to_tag] || this.dialogs[request.call_id + request.to_tag + request.from_tag] || null; - }; - - /** - * Get the subscription which has not been confirmed to which the request belongs to, if any - * @private - * @param {SIP.IncomingRequest} - * @returns {SIP.Subscription|null} - */ - UA.prototype.findEarlySubscription = function (request) { - return this.earlySubscriptions[request.call_id + request.to_tag + request.getHeader('event')] || null; - }; - - /** - * Retrieve the next server to which connect. - * @private - * @returns {Object} ws_server - */ - UA.prototype.getNextWsServer = function () { - // Order servers by weight - var idx, - length, - ws_server, - candidates = []; - - length = this.configuration.wsServers.length; - for (idx = 0; idx < length; idx++) { - ws_server = this.configuration.wsServers[idx]; - - if (ws_server.status === SIP.Transport.C.STATUS_ERROR) { - continue; - } else if (candidates.length === 0) { - candidates.push(ws_server); - } else if (ws_server.weight > candidates[0].weight) { - candidates = [ws_server]; - } else if (ws_server.weight === candidates[0].weight) { - candidates.push(ws_server); - } - } - - idx = Math.floor(Math.random() * candidates.length); - - return candidates[idx]; - }; - - /** - * Close all sessions on transport error. - * @private - */ - UA.prototype.closeSessionsOnTransportError = function () { - var idx; - - // Run _transportError_ for every Session - for (idx in this.sessions) { - this.sessions[idx].onTransportError(); - } - // Call registerContext _onTransportClosed_ - this.registerContext.onTransportClosed(); - }; - - UA.prototype.recoverTransport = function (ua) { - var idx, length, k, nextRetry, count, server; - - ua = ua || this; - count = ua.transportRecoverAttempts; - - length = ua.configuration.wsServers.length; - for (idx = 0; idx < length; idx++) { - ua.configuration.wsServers[idx].status = 0; - } - - server = ua.getNextWsServer(); - - k = Math.floor(Math.random() * Math.pow(2, count) + 1); - nextRetry = k * ua.configuration.connectionRecoveryMinInterval; - - if (nextRetry > ua.configuration.connectionRecoveryMaxInterval) { - this.logger.log('time for next connection attempt exceeds connectionRecoveryMaxInterval, resetting counter'); - nextRetry = ua.configuration.connectionRecoveryMinInterval; - count = 0; - } - - this.logger.log('next connection attempt in ' + nextRetry + ' seconds'); - - this.transportRecoveryTimer = SIP.Timers.setTimeout(function () { - ua.transportRecoverAttempts = count + 1; - new SIP.Transport(ua, server); - }, nextRetry * 1000); - }; - - function checkAuthenticationFactory(authenticationFactory) { - if (!(authenticationFactory instanceof Function)) { - return; - } - if (!authenticationFactory.initialize) { - authenticationFactory.initialize = function initialize() { - return SIP.Utils.Promise.resolve(); - }; - } - return authenticationFactory; - } - - /** - * Configuration load. - * @private - * returns {Boolean} - */ - UA.prototype.loadConfig = function (configuration) { - // Settings and default values - var parameter, - value, - checked_value, - hostportParams, - registrarServer, - settings = { - /* Host address - * Value to be set in Via sent_by and host part of Contact FQDN - */ - viaHost: SIP.Utils.createRandomToken(12) + '.invalid', - - uri: new SIP.URI('sip', 'anonymous.' + SIP.Utils.createRandomToken(6), 'anonymous.invalid', null, null), - wsServers: [{ - scheme: 'WSS', - sip_uri: '', - status: 0, - weight: 0, - ws_uri: 'wss://edge.sip.onsip.com' - }], - - //Custom Configuration Settings - custom: {}, - - //Display name - displayName: '', - - // Password - password: null, - - // Registration parameters - registerExpires: 600, - register: true, - registrarServer: null, - - // Transport related parameters - wsServerMaxReconnection: 3, - wsServerReconnectionTimeout: 4, - - connectionRecoveryMinInterval: 2, - connectionRecoveryMaxInterval: 30, - - keepAliveInterval: 0, - - extraSupported: [], - - usePreloadedRoute: false, - - //string to be inserted into User-Agent request header - userAgentString: SIP.C.USER_AGENT, - - // Session parameters - noAnswerTimeout: 60, - - // Logging parameters - traceSip: false, - - // Hacks - hackViaTcp: false, - hackIpInContact: false, - hackWssInTransport: false, - hackAllowUnregisteredOptionTags: false, - - // Session Description Handler Options - sessionDescriptionHandlerFactoryOptions: { - constraints: {}, - peerConnectionOptions: {} - }, - - contactName: SIP.Utils.createRandomToken(8), // user name in user part - contactTransport: 'ws', - forceRport: false, - - //autostarting - autostart: true, - autostop: true, - - //Reliable Provisional Responses - rel100: SIP.C.supported.UNSUPPORTED, - - // Replaces header (RFC 3891) - // http://tools.ietf.org/html/rfc3891 - replaces: SIP.C.supported.UNSUPPORTED, - - sessionDescriptionHandlerFactory: __webpack_require__(27)(SIP).defaultFactory, - - authenticationFactory: checkAuthenticationFactory(function authenticationFactory(ua) { - return new SIP.DigestAuthentication(ua); - }), - - allowLegacyNotifications: false, - - allowOutOfDialogRefers: false - }; - - // Pre-Configuration - function aliasUnderscored(parameter, logger) { - var underscored = parameter.replace(/([a-z][A-Z])/g, function (m) { - return m[0] + '_' + m[1].toLowerCase(); - }); - - if (parameter === underscored) { - return; - } - - var hasParameter = configuration.hasOwnProperty(parameter); - if (configuration.hasOwnProperty(underscored)) { - logger.warn(underscored + ' is deprecated, please use ' + parameter); - if (hasParameter) { - logger.warn(parameter + ' overriding ' + underscored); - } - } - - configuration[parameter] = hasParameter ? configuration[parameter] : configuration[underscored]; - } - - var configCheck = this.getConfigurationCheck(); - - // Check Mandatory parameters - for (parameter in configCheck.mandatory) { - aliasUnderscored(parameter, this.logger); - if (!configuration.hasOwnProperty(parameter)) { - throw new SIP.Exceptions.ConfigurationError(parameter); - } else { - value = configuration[parameter]; - checked_value = configCheck.mandatory[parameter](value); - if (checked_value !== undefined) { - settings[parameter] = checked_value; - } else { - throw new SIP.Exceptions.ConfigurationError(parameter, value); - } - } - } - - // Check Optional parameters - for (parameter in configCheck.optional) { - aliasUnderscored(parameter, this.logger); - if (configuration.hasOwnProperty(parameter)) { - value = configuration[parameter]; - - // If the parameter value is an empty array, but shouldn't be, apply its default value. - if (value instanceof Array && value.length === 0) { - continue; - } - - // If the parameter value is null, empty string, or undefined then apply its default value. - if (value === null || value === "" || value === undefined) { - continue; - } - // If it's a number with NaN value then also apply its default value. - // NOTE: JS does not allow "value === NaN", the following does the work: - else if (typeof value === 'number' && isNaN(value)) { - continue; - } - - checked_value = configCheck.optional[parameter](value); - if (checked_value !== undefined) { - settings[parameter] = checked_value; - } else { - throw new SIP.Exceptions.ConfigurationError(parameter, value); - } - } - } - - // Sanity Checks - - // Connection recovery intervals - if (settings.connectionRecoveryMaxInterval < settings.connectionRecoveryMinInterval) { - throw new SIP.Exceptions.ConfigurationError('connectionRecoveryMaxInterval', settings.connectionRecoveryMaxInterval); - } - - // Post Configuration Process - - // Allow passing 0 number as displayName. - if (settings.displayName === 0) { - settings.displayName = '0'; - } - - // Instance-id for GRUU - if (!settings.instanceId) { - settings.instanceId = SIP.Utils.newUUID(); - } - - // sipjsId instance parameter. Static random tag of length 5 - settings.sipjsId = SIP.Utils.createRandomToken(5); - - // String containing settings.uri without scheme and user. - hostportParams = settings.uri.clone(); - hostportParams.user = null; - settings.hostportParams = hostportParams.toRaw().replace(/^sip:/i, ''); - - /* Check whether authorizationUser is explicitly defined. - * Take 'settings.uri.user' value if not. - */ - if (!settings.authorizationUser) { - settings.authorizationUser = settings.uri.user; - } - - /* If no 'registrarServer' is set use the 'uri' value without user portion. */ - if (!settings.registrarServer) { - registrarServer = settings.uri.clone(); - registrarServer.user = null; - settings.registrarServer = registrarServer; - } - - // User noAnswerTimeout - settings.noAnswerTimeout = settings.noAnswerTimeout * 1000; - - // Via Host - if (settings.hackIpInContact) { - if (typeof settings.hackIpInContact === 'boolean') { - settings.viaHost = SIP.Utils.getRandomTestNetIP(); - } else if (typeof settings.hackIpInContact === 'string') { - settings.viaHost = settings.hackIpInContact; - } - } - - // Contact transport parameter - if (settings.hackWssInTransport) { - settings.contactTransport = 'wss'; - } - - this.contact = { - pub_gruu: null, - temp_gruu: null, - uri: new SIP.URI('sip', settings.contactName, settings.viaHost, null, { transport: settings.contactTransport }), - toString: function toString(options) { - options = options || {}; - - var anonymous = options.anonymous || null, - outbound = options.outbound || null, - contact = '<'; - - if (anonymous) { - contact += (this.temp_gruu || 'sip:anonymous@anonymous.invalid;transport=' + settings.contactTransport).toString(); - } else { - contact += (this.pub_gruu || this.uri).toString(); - } - - if (outbound) { - contact += ';ob'; - } - - contact += '>'; - - return contact; - } - }; - - var skeleton = {}; - // Fill the value of the configuration_skeleton - for (parameter in settings) { - skeleton[parameter] = { - value: settings[parameter], - writable: parameter === 'register' || parameter === 'custom', - configurable: false - }; - } - - Object.defineProperties(this.configuration, skeleton); - - this.logger.log('configuration parameters after validation:'); - for (parameter in settings) { - switch (parameter) { - case 'uri': - case 'registrarServer': - case 'sessionDescriptionHandlerFactory': - this.logger.log('· ' + parameter + ': ' + settings[parameter]); - break; - case 'password': - this.logger.log('· ' + parameter + ': ' + 'NOT SHOWN'); - break; - default: - this.logger.log('· ' + parameter + ': ' + JSON.stringify(settings[parameter])); - } - } - - return; - }; - - /** - * Configuration checker. - * @private - * @return {Boolean} - */ - UA.prototype.getConfigurationCheck = function () { - return { - mandatory: {}, - - optional: { - - uri: function uri(_uri) { - var parsed; - - if (!/^sip:/i.test(_uri)) { - _uri = SIP.C.SIP + ':' + _uri; - } - parsed = SIP.URI.parse(_uri); - - if (!parsed) { - return; - } else if (!parsed.user) { - return; - } else { - return parsed; - } - }, - - //Note: this function used to call 'this.logger.error' but calling 'this' with anything here is invalid - wsServers: function wsServers(_wsServers) { - var idx, length, url; - - /* Allow defining wsServers parameter as: - * String: "host" - * Array of Strings: ["host1", "host2"] - * Array of Objects: [{ws_uri:"host1", weight:1}, {ws_uri:"host2", weight:0}] - * Array of Objects and Strings: [{ws_uri:"host1"}, "host2"] - */ - if (typeof _wsServers === 'string') { - _wsServers = [{ ws_uri: _wsServers }]; - } else if (_wsServers instanceof Array) { - length = _wsServers.length; - for (idx = 0; idx < length; idx++) { - if (typeof _wsServers[idx] === 'string') { - _wsServers[idx] = { ws_uri: _wsServers[idx] }; - } - } - } else { - return; - } - - if (_wsServers.length === 0) { - return false; - } - - length = _wsServers.length; - for (idx = 0; idx < length; idx++) { - if (!_wsServers[idx].ws_uri) { - return; - } - if (_wsServers[idx].weight && !Number(_wsServers[idx].weight)) { - return; - } - - url = SIP.Grammar.parse(_wsServers[idx].ws_uri, 'absoluteURI'); - - if (url === -1) { - return; - } else if (['wss', 'ws', 'udp'].indexOf(url.scheme) < 0) { - return; - } else { - _wsServers[idx].sip_uri = ''; - - if (!_wsServers[idx].weight) { - _wsServers[idx].weight = 0; - } - - _wsServers[idx].status = 0; - _wsServers[idx].scheme = url.scheme.toUpperCase(); - } - } - return _wsServers; - }, - - authorizationUser: function authorizationUser(_authorizationUser) { - if (SIP.Grammar.parse('"' + _authorizationUser + '"', 'quoted_string') === -1) { - return; - } else { - return _authorizationUser; - } - }, - - connectionRecoveryMaxInterval: function connectionRecoveryMaxInterval(_connectionRecoveryMaxInterval) { - var value; - if (SIP.Utils.isDecimal(_connectionRecoveryMaxInterval)) { - value = Number(_connectionRecoveryMaxInterval); - if (value > 0) { - return value; - } - } - }, - - connectionRecoveryMinInterval: function connectionRecoveryMinInterval(_connectionRecoveryMinInterval) { - var value; - if (SIP.Utils.isDecimal(_connectionRecoveryMinInterval)) { - value = Number(_connectionRecoveryMinInterval); - if (value > 0) { - return value; - } - } - }, - - displayName: function displayName(_displayName) { - if (SIP.Grammar.parse('"' + _displayName + '"', 'displayName') === -1) { - return; - } else { - return _displayName; - } - }, - - hackViaTcp: function hackViaTcp(_hackViaTcp) { - if (typeof _hackViaTcp === 'boolean') { - return _hackViaTcp; - } - }, - - hackIpInContact: function hackIpInContact(_hackIpInContact) { - if (typeof _hackIpInContact === 'boolean') { - return _hackIpInContact; - } else if (typeof _hackIpInContact === 'string' && SIP.Grammar.parse(_hackIpInContact, 'host') !== -1) { - return _hackIpInContact; - } - }, - - hackWssInTransport: function hackWssInTransport(_hackWssInTransport) { - if (typeof _hackWssInTransport === 'boolean') { - return _hackWssInTransport; - } - }, - - hackAllowUnregisteredOptionTags: function hackAllowUnregisteredOptionTags(_hackAllowUnregisteredOptionTags) { - if (typeof _hackAllowUnregisteredOptionTags === 'boolean') { - return _hackAllowUnregisteredOptionTags; - } - }, - - contactTransport: function contactTransport(_contactTransport) { - if (typeof _contactTransport === 'string') { - return _contactTransport; - } - }, - - forceRport: function forceRport(_forceRport) { - if (typeof _forceRport === 'boolean') { - return _forceRport; - } - }, - - instanceId: function instanceId(_instanceId) { - if (typeof _instanceId !== 'string') { - return; - } - - if (/^uuid:/i.test(_instanceId)) { - _instanceId = _instanceId.substr(5); - } - - if (SIP.Grammar.parse(_instanceId, 'uuid') === -1) { - return; - } else { - return _instanceId; - } - }, - - keepAliveInterval: function keepAliveInterval(_keepAliveInterval) { - var value; - if (SIP.Utils.isDecimal(_keepAliveInterval)) { - value = Number(_keepAliveInterval); - if (value > 0) { - return value; - } - } - }, - - extraSupported: function extraSupported(optionTags) { - var idx, length; - - if (!(optionTags instanceof Array)) { - return; - } - - length = optionTags.length; - for (idx = 0; idx < length; idx++) { - if (typeof optionTags[idx] !== 'string') { - return; - } - } - - return optionTags; - }, - - noAnswerTimeout: function noAnswerTimeout(_noAnswerTimeout) { - var value; - if (SIP.Utils.isDecimal(_noAnswerTimeout)) { - value = Number(_noAnswerTimeout); - if (value > 0) { - return value; - } - } - }, - - password: function password(_password) { - return String(_password); - }, - - rel100: function rel100(_rel) { - if (_rel === SIP.C.supported.REQUIRED) { - return SIP.C.supported.REQUIRED; - } else if (_rel === SIP.C.supported.SUPPORTED) { - return SIP.C.supported.SUPPORTED; - } else { - return SIP.C.supported.UNSUPPORTED; - } - }, - - replaces: function replaces(_replaces) { - if (_replaces === SIP.C.supported.REQUIRED) { - return SIP.C.supported.REQUIRED; - } else if (_replaces === SIP.C.supported.SUPPORTED) { - return SIP.C.supported.SUPPORTED; - } else { - return SIP.C.supported.UNSUPPORTED; - } - }, - - register: function register(_register) { - if (typeof _register === 'boolean') { - return _register; - } - }, - - registerExpires: function registerExpires(_registerExpires) { - var value; - if (SIP.Utils.isDecimal(_registerExpires)) { - value = Number(_registerExpires); - if (value > 0) { - return value; - } - } - }, - - registrarServer: function registrarServer(_registrarServer) { - var parsed; - - if (typeof _registrarServer !== 'string') { - return; - } - - if (!/^sip:/i.test(_registrarServer)) { - _registrarServer = SIP.C.SIP + ':' + _registrarServer; - } - parsed = SIP.URI.parse(_registrarServer); - - if (!parsed) { - return; - } else if (parsed.user) { - return; - } else { - return parsed; - } - }, - - traceSip: function traceSip(_traceSip) { - if (typeof _traceSip === 'boolean') { - return _traceSip; - } - }, - - userAgentString: function userAgentString(_userAgentString) { - if (typeof _userAgentString === 'string') { - return _userAgentString; - } - }, - - usePreloadedRoute: function usePreloadedRoute(_usePreloadedRoute) { - if (typeof _usePreloadedRoute === 'boolean') { - return _usePreloadedRoute; - } - }, - - wsServerMaxReconnection: function wsServerMaxReconnection(_wsServerMaxReconnection) { - var value; - if (SIP.Utils.isDecimal(_wsServerMaxReconnection)) { - value = Number(_wsServerMaxReconnection); - if (value > 0) { - return value; - } - } - }, - - wsServerReconnectionTimeout: function wsServerReconnectionTimeout(_wsServerReconnectionTimeout) { - var value; - if (SIP.Utils.isDecimal(_wsServerReconnectionTimeout)) { - value = Number(_wsServerReconnectionTimeout); - if (value > 0) { - return value; - } - } - }, - - autostart: function autostart(_autostart) { - if (typeof _autostart === 'boolean') { - return _autostart; - } - }, - - autostop: function autostop(_autostop) { - if (typeof _autostop === 'boolean') { - return _autostop; - } - }, - - sessionDescriptionHandlerFactory: function sessionDescriptionHandlerFactory(_sessionDescriptionHandlerFactory) { - if (_sessionDescriptionHandlerFactory instanceof Function) { - return _sessionDescriptionHandlerFactory; - } - }, - - sessionDescriptionHandlerFactoryOptions: function sessionDescriptionHandlerFactoryOptions(options) { - if ((typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object') { - return options; - } - }, - - authenticationFactory: checkAuthenticationFactory, - - allowLegacyNotifications: function allowLegacyNotifications(_allowLegacyNotifications) { - if (typeof _allowLegacyNotifications === 'boolean') { - return _allowLegacyNotifications; - } - }, - - custom: function custom(_custom) { - if ((typeof _custom === 'undefined' ? 'undefined' : _typeof(_custom)) === 'object') { - return _custom; - } - }, - - contactName: function contactName(_contactName) { - if (typeof _contactName === 'string') { - return _contactName; - } - } - } - }; - }; - - UA.C = C; - SIP.UA = UA; -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -/** - * @fileoverview SessionDescriptionHandler - */ - -/* SessionDescriptionHandler - * @class PeerConnection helper Class. - * @param {SIP.Session} session - * @param {Object} [options] - */ - -module.exports = function (SIP) { - - // Constructor - var SessionDescriptionHandler = function SessionDescriptionHandler(session, options) { - // TODO: Validate the options - this.options = options || {}; - - this.logger = session.ua.getLogger('sip.invitecontext.sessionDescriptionHandler', session.id); - this.session = session; - - this.CONTENT_TYPE = 'application/sdp'; - - this.modifiers = this.options.modifiers || []; - if (!Array.isArray(this.modifiers)) { - this.modifiers = [this.modifiers]; - } - - var environment = global.window || global; - this.WebRTC = { - MediaStream: environment.MediaStream, - getUserMedia: environment.navigator.mediaDevices.getUserMedia.bind(environment.navigator.mediaDevices), - RTCPeerConnection: environment.RTCPeerConnection, - RTCSessionDescription: environment.RTCSessionDescription - }; - - this.iceGatheringDeferred = null; - this.iceGatheringTimeout = false; - this.iceGatheringTimer = null; - - this.initPeerConnection(this.options.peerConnectionOptions); - - this.constraints = this.checkAndDefaultConstraints(this.options.constraints); - - this.session.emit('SessionDescriptionHandler-created', this); - }; - - /** - * @param {SIP.Session} session - * @param {Object} [options] - */ - - SessionDescriptionHandler.defaultFactory = function defaultFactory(session, options) { - return new SessionDescriptionHandler(session, options); - }; - - SessionDescriptionHandler.prototype = Object.create(SIP.SessionDescriptionHandler.prototype, { - // Functions the sesssion can use - - /** - * Destructor - */ - close: { writable: true, value: function value() { - this.logger.log('closing PeerConnection'); - // have to check signalingState since this.close() gets called multiple times - if (this.peerConnection && this.peerConnection.signalingState !== 'closed') { - if (this.peerConnection.getSenders) { - this.peerConnection.getSenders().forEach(function (sender) { - if (sender.track) { - sender.track.stop(); - } - }); - } else { - this.logger.warn('Using getLocalStreams which is deprecated'); - this.peerConnection.getLocalStreams().forEach(function (stream) { - stream.getTracks().forEach(function (track) { - track.stop(); - }); - }); - } - if (this.peerConnection.getReceivers) { - this.peerConnection.getReceivers().forEach(function (receiver) { - if (receiver.track) { - receiver.track.stop(); - } - }); - } else { - this.logger.warn('Using getRemoteStreams which is deprecated'); - this.peerConnection.getRemoteStreams().forEach(function (stream) { - stream.getTracks().forEach(function (track) { - track.stop(); - }); - }); - } - this.resetIceGatheringComplete(); - this.peerConnection.close(); - } - } }, - - /** - * Gets the local description from the underlying media implementation - * @param {Object} [options] Options object to be used by getDescription - * @param {MediaStreamConstraints} [options.constraints] MediaStreamConstraints https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints - * @param {Object} [options.peerConnectionOptions] If this is set it will recreate the peer connection with the new options - * @param {Array} [modifiers] Array with one time use description modifiers - * @returns {Promise} Promise that resolves with the local description to be used for the session - */ - getDescription: { writable: true, value: function value(options, modifiers) { - var self = this; - var shouldAcquireMedia = true; - - if (this.session.disableRenegotiation) { - this.logger.warn("The flag \"disableRenegotiation\" is set to true for this session description handler. We will not try to renegotiate."); - return SIP.Utils.Promise.reject(new SIP.Exceptions.RenegotiationError("disableRenegotiation flag set to true for this session description handler")); - } - - options = options || {}; - if (options.peerConnectionOptions) { - this.initPeerConnection(options.peerConnectionOptions); - } - - // Merge passed constraints with saved constraints and save - var newConstraints = Object.assign({}, this.constraints, options.constraints); - newConstraints = this.checkAndDefaultConstraints(newConstraints); - if (JSON.stringify(newConstraints) !== JSON.stringify(this.constraints)) { - this.constraints = newConstraints; - } else { - shouldAcquireMedia = false; - } - - modifiers = modifiers || []; - if (!Array.isArray(modifiers)) { - modifiers = [modifiers]; - } - modifiers = modifiers.concat(this.modifiers); - - // Check to see if the peerConnection already has a local description - if (!shouldAcquireMedia && this.peerConnection.localDescription && this.peerConnection.localDescription.sdp && this.peerConnection.localDescription.sdp !== '') { - return this.createOfferOrAnswer(options.RTCOfferOptions, modifiers).then(function (sdp) { - return { - body: sdp, - contentType: self.CONTENT_TYPE - }; - }); - } - - // GUM and set myself up - self.logger.log('acquiring local media'); - // TODO: Constraints should be named MediaStreamConstraints - return this.acquire(self.constraints).then(function acquireSucceeded(streams) { - self.logger.log('acquired local media streams'); - return streams; - }, function acquireFailed(err) { - self.logger.error('unable to acquire streams'); - self.logger.error(err); - throw err; - }).then(function addStreams(streams) { - try { - streams = [].concat(streams); - streams.forEach(function (stream) { - if (self.peerConnection.addTrack) { - stream.getTracks().forEach(function (track) { - self.peerConnection.addTrack(track, stream); - }); - } else { - // Chrome 59 does not support addTrack - self.peerConnection.addStream(stream); - } - }, this); - } catch (e) { - self.logger.error('error adding stream'); - self.logger.error(e); - return SIP.Utils.Promise.reject(e); - } - return SIP.Utils.Promise.resolve(); - }).then(function streamAdditionSucceeded() { - return self.createOfferOrAnswer(options.RTCOfferOptions, modifiers); - }).then(function (sdp) { - return { - body: sdp, - contentType: self.CONTENT_TYPE - }; - }).catch(function (e) { - this.session.disableRenegotiation = true; - throw e; - }); - } }, - - /** - * Check if the Session Description Handler can handle the Content-Type described by a SIP Message - * @param {String} contentType The content type that is in the SIP Message - * @returns {boolean} - */ - hasDescription: { writable: true, value: function hasDescription(contentType) { - return contentType === this.CONTENT_TYPE; - } }, - - /** - * The modifier that should be used when the session would like to place the call on hold - * @param {String} [sdp] The description that will be modified - * @returns {Promise} Promise that resolves with modified SDP - */ - holdModifier: { writable: true, value: function holdModifier(description) { - if (!/a=(sendrecv|sendonly|recvonly|inactive)/.test(description.sdp)) { - description.sdp = description.sdp.replace(/(m=[^\r]*\r\n)/g, '$1a=sendonly\r\n'); - } else { - description.sdp = description.sdp.replace(/a=sendrecv\r\n/g, 'a=sendonly\r\n'); - description.sdp = description.sdp.replace(/a=recvonly\r\n/g, 'a=inactive\r\n'); - } - return SIP.Utils.Promise.resolve(description); - } }, - - /** - * Set the remote description to the underlying media implementation - * @param {String} sessionDescription The description provided by a SIP message to be set on the media implementation - * @param {Object} [options] Options object to be used by getDescription - * @param {MediaStreamConstraints} [options.constraints] MediaStreamConstraints https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints - * @param {Object} [options.peerConnectionOptions] If this is set it will recreate the peer connection with the new options - * @param {Array} [modifiers] Array with one time use description modifiers - * @returns {Promise} Promise that resolves once the description is set - */ - setDescription: { writable: true, value: function setDescription(sessionDescription, options, modifiers) { - var self = this; - - // https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser - var isFirefox = typeof InstallTrigger !== 'undefined'; - if (!this.session.disableRenegotiation && isFirefox && this.peerConnection && this.isVideoHold(sessionDescription)) { - this.session.disableRenegotiation = true; - } - - if (this.session.disableRenegotiation) { - this.logger.warn("The flag \"disableRenegotiation\" is set to true for this session description handler. We will not try to renegotiate."); - return SIP.Utils.Promise.reject(new SIP.Exceptions.RenegotiationError("disableRenegotiation flag set to true for this session description handler")); - } - - options = options || {}; - if (options.peerConnectionOptions) { - this.initPeerConnection(options.peerConnectionOptions); - } - - // Merge passed constraints with saved constraints and save - this.constraints = Object.assign({}, this.constraints, options.constraints); - this.constraints = this.checkAndDefaultConstraints(this.constraints); - - modifiers = modifiers || []; - if (!Array.isArray(modifiers)) { - modifiers = [modifiers]; - } - modifiers = modifiers.concat(this.modifiers); - - var description = { - type: this.hasOffer('local') ? 'answer' : 'offer', - sdp: sessionDescription - }; - - return SIP.Utils.reducePromises(modifiers, description).catch(function modifierError(e) { - self.logger.error("The modifiers did not resolve successfully"); - self.logger.error(e); - throw e; - }).then(function (modifiedDescription) { - self.emit('setDescription', modifiedDescription); - return self.peerConnection.setRemoteDescription(new self.WebRTC.RTCSessionDescription(modifiedDescription)); - }).catch(function setRemoteDescriptionError(e) { - self.session.disableRenegotiation = true; - self.logger.error(e); - self.emit('peerConnection-setRemoteDescriptionFailed', e); - throw e; - }).then(function setRemoteDescriptionSuccess() { - if (self.peerConnection.getReceivers) { - self.emit('setRemoteDescription', self.peerConnection.getReceivers()); - } else { - self.emit('setRemoteDescription', self.peerConnection.getRemoteStreams()); - } - self.emit('confirmed', self); - }); - } }, - - // Internal functions - createOfferOrAnswer: { writable: true, value: function createOfferOrAnswer(RTCOfferOptions, modifiers) { - var self = this; - var methodName; - var pc = this.peerConnection; - - RTCOfferOptions = RTCOfferOptions || {}; - - methodName = self.hasOffer('remote') ? 'createAnswer' : 'createOffer'; - - return pc[methodName](RTCOfferOptions).catch(function methodError(e) { - self.emit('peerConnection-' + methodName + 'Failed', e); - throw e; - }).then(function (sdp) { - return SIP.Utils.reducePromises(modifiers, sdp); - }).then(function (sdp) { - self.logger.log(sdp); - return pc.setLocalDescription(sdp); - }).catch(function localDescError(e) { - self.emit('peerConnection-SetLocalDescriptionFailed', e); - throw e; - }).then(function onSetLocalDescriptionSuccess() { - return self.waitForIceGatheringComplete(); - }).then(function readySuccess() { - var localDescription = self.peerConnection.localDescription; - return SIP.Utils.reducePromises(modifiers, localDescription); - }).then(function (localDescription) { - self.emit('getDescription', localDescription); - return localDescription.sdp; - }).catch(function createOfferOrAnswerError(e) { - self.logger.error(e); - // TODO: Not sure if this is correct - throw new SIP.Exceptions.GetDescriptionError(e); - }); - } }, - - addDefaultIceCheckingTimeout: { writable: true, value: function addDefaultIceCheckingTimeout(peerConnectionOptions) { - if (peerConnectionOptions.iceCheckingTimeout === undefined) { - peerConnectionOptions.iceCheckingTimeout = 5000; - } - return peerConnectionOptions; - } }, - - addDefaultIceServers: { writable: true, value: function addDefaultIceServers(rtcConfiguration) { - if (!rtcConfiguration.iceServers) { - rtcConfiguration.iceServers = [{ urls: 'stun:stun.l.google.com:19302' }]; - } - return rtcConfiguration; - } }, - - checkAndDefaultConstraints: { writable: true, value: function checkAndDefaultConstraints(constraints) { - var defaultConstraints = { audio: true, video: true }; - constraints = constraints || defaultConstraints; - // Empty object check - if (Object.keys(constraints).length === 0 && constraints.constructor === Object) { - return defaultConstraints; - } - return constraints; - } }, - - initPeerConnection: { writable: true, value: function initPeerConnection(options) { - var self = this; - options = options || {}; - options = this.addDefaultIceCheckingTimeout(options); - options.rtcConfiguration = options.rtcConfiguration || {}; - options.rtcConfiguration = this.addDefaultIceServers(options.rtcConfiguration); - - this.logger.log('initPeerConnection'); - - if (this.peerConnection) { - this.logger.log('Already have a peer connection for this session. Tearing down.'); - this.resetIceGatheringComplete(); - this.peerConnection.close(); - } - - this.peerConnection = new this.WebRTC.RTCPeerConnection(options.rtcConfiguration); - - this.logger.log('New peer connection created'); - this.session.emit('peerConnection-created', this.peerConnection); - - this.peerConnection.ontrack = function (e) { - self.logger.log('track added'); - self.emit('addTrack', e); - }; - - this.peerConnection.onaddstream = function (e) { - self.logger.warn('Using deprecated stream API'); - self.logger.log('stream added'); - self.emit('addStream', e); - }; - - // TODO: There is no remove track listener - this.peerConnection.onremovestream = function (e) { - self.logger.log('stream removed: ' + e.stream.id); - }; - - this.peerConnection.onicecandidate = function (e) { - self.emit('iceCandidate', e); - if (e.candidate) { - self.logger.log('ICE candidate received: ' + (e.candidate.candidate === null ? null : e.candidate.candidate.trim())); - } - }; - - this.peerConnection.onicegatheringstatechange = function () { - self.logger.log('RTCIceGatheringState changed: ' + this.iceGatheringState); - switch (this.iceGatheringState) { - case 'gathering': - self.emit('iceGathering', this); - if (!self.iceGatheringTimer && options.iceCheckingTimeout) { - self.iceGatheringTimeout = false; - self.iceGatheringTimer = SIP.Timers.setTimeout(function () { - self.logger.log('RTCIceChecking Timeout Triggered after ' + options.iceCheckingTimeout + ' milliseconds'); - self.iceGatheringTimeout = true; - self.triggerIceGatheringComplete(); - }, options.iceCheckingTimeout); - } - break; - case 'complete': - self.triggerIceGatheringComplete(); - break; - } - }; - - this.peerConnection.oniceconnectionstatechange = function () { - //need e for commented out case - var stateEvent; - - switch (this.iceConnectionState) { - case 'new': - stateEvent = 'iceConnection'; - break; - case 'checking': - stateEvent = 'iceConnectionChecking'; - break; - case 'connected': - stateEvent = 'iceConnectionConnected'; - break; - case 'completed': - stateEvent = 'iceConnectionCompleted'; - break; - case 'failed': - stateEvent = 'iceConnectionFailed'; - break; - case 'disconnected': - stateEvent = 'iceConnectionDisconnected'; - break; - case 'closed': - stateEvent = 'iceConnectionClosed'; - break; - default: - self.logger.warn('Unknown iceConnection state:', this.iceConnectionState); - return; - } - self.emit(stateEvent, this); - }; - } }, - - acquire: { writable: true, value: function acquire(constraints) { - // Default audio & video to true - constraints = this.checkAndDefaultConstraints(constraints); - - return new SIP.Utils.Promise(function (resolve, reject) { - /* - * Make the call asynchronous, so that ICCs have a chance - * to define callbacks to `userMediaRequest` - */ - this.emit('userMediaRequest', constraints); - - var emitThenCall = function (eventName, callback) { - var callbackArgs = Array.prototype.slice.call(arguments, 2); - // Emit with all of the arguments from the real callback. - var newArgs = [eventName].concat(callbackArgs); - this.emit.apply(this, newArgs); - return callback.apply(null, callbackArgs); - }.bind(this); - - if (constraints.audio || constraints.video) { - this.WebRTC.getUserMedia(constraints).then(emitThenCall.bind(this, 'userMedia', function (streams) { - resolve(streams); - }), emitThenCall.bind(this, 'userMediaFailed', function (e) { - reject(e); - throw e; - })); - } else { - // Local streams were explicitly excluded. - resolve([]); - } - }.bind(this)); - } }, - - isVideoHold: { writable: true, value: function isVideoHold(description) { - if (description.search(/^(m=video.*?)[\s\S]*^(a=sendonly?)/gm) !== -1) { - return true; - } - return false; - } }, - - hasOffer: { writable: true, value: function hasOffer(where) { - var offerState = 'have-' + where + '-offer'; - return this.peerConnection.signalingState === offerState; - } }, - - // ICE gathering state handling - - isIceGatheringComplete: { writable: true, value: function isIceGatheringComplete() { - return this.peerConnection.iceGatheringState === 'complete' || this.iceGatheringTimeout; - } }, - - resetIceGatheringComplete: { writable: true, value: function rejectIceGatheringComplete() { - this.iceGatheringTimeout = false; - - if (this.iceGatheringTimer) { - SIP.Timers.clearTimeout(this.iceGatheringTimer); - this.iceGatheringTimer = null; - } - - if (this.iceGatheringDeferred) { - this.iceGatheringDeferred.reject(); - this.iceGatheringDeferred = null; - } - } }, - - triggerIceGatheringComplete: { writable: true, value: function triggerIceGatheringComplete() { - if (this.isIceGatheringComplete()) { - this.emit('iceGatheringComplete', this); - - if (this.iceGatheringTimer) { - SIP.Timers.clearTimeout(this.iceGatheringTimer); - this.iceGatheringTimer = null; - } - - if (this.iceGatheringDeferred) { - this.iceGatheringDeferred.resolve(); - this.iceGatheringDeferred = null; - } - } - } }, - - waitForIceGatheringComplete: { writable: true, value: function waitForIceGatheringComplete() { - if (this.isIceGatheringComplete()) { - return SIP.Utils.Promise.resolve(); - } else if (!this.isIceGatheringDeferred) { - this.iceGatheringDeferred = SIP.Utils.defer(); - } - return this.iceGatheringDeferred.promise; - } } - }); - - return SessionDescriptionHandler; -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - -/***/ }), -/* 28 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview Incoming SIP Message Sanity Check - */ - -/** - * SIP message sanity check. - * @augments SIP - * @function - * @param {SIP.IncomingMessage} message - * @param {SIP.UA} ua - * @param {SIP.Transport} transport - * @returns {Boolean} - */ - -module.exports = function (SIP) { - var sanityCheck, - requests = [], - responses = [], - all = []; - - // Reply - function reply(status_code, message, transport) { - var to, - response = SIP.Utils.buildStatusLine(status_code), - vias = message.getHeaders('via'), - length = vias.length, - idx = 0; - - for (idx; idx < length; idx++) { - response += "Via: " + vias[idx] + "\r\n"; - } - - to = message.getHeader('To'); - - if (!message.to_tag) { - to += ';tag=' + SIP.Utils.newTag(); - } - - response += "To: " + to + "\r\n"; - response += "From: " + message.getHeader('From') + "\r\n"; - response += "Call-ID: " + message.call_id + "\r\n"; - response += "CSeq: " + message.cseq + " " + message.method + "\r\n"; - response += "\r\n"; - - transport.send(response); - } - - /* - * Sanity Check for incoming Messages - * - * Requests: - * - _rfc3261_8_2_2_1_ Receive a Request with a non supported URI scheme - * - _rfc3261_16_3_4_ Receive a Request already sent by us - * Does not look at via sent-by but at sipjsId, which is inserted as - * a prefix in all initial requests generated by the ua - * - _rfc3261_18_3_request_ Body Content-Length - * - _rfc3261_8_2_2_2_ Merged Requests - * - * Responses: - * - _rfc3261_8_1_3_3_ Multiple Via headers - * - _rfc3261_18_1_2_ sent-by mismatch - * - _rfc3261_18_3_response_ Body Content-Length - * - * All: - * - Minimum headers in a SIP message - */ - - // Sanity Check functions for requests - function rfc3261_8_2_2_1(message, ua, transport) { - if (!message.ruri || message.ruri.scheme !== 'sip') { - reply(416, message, transport); - return false; - } - } - - function rfc3261_16_3_4(message, ua, transport) { - if (!message.to_tag) { - if (message.call_id.substr(0, 5) === ua.configuration.sipjsId) { - reply(482, message, transport); - return false; - } - } - } - - function rfc3261_18_3_request(message, ua, transport) { - var len = SIP.Utils.str_utf8_length(message.body), - contentLength = message.getHeader('content-length'); - - if (len < contentLength) { - reply(400, message, transport); - return false; - } - } - - function rfc3261_8_2_2_2(message, ua, transport) { - var tr, - idx, - fromTag = message.from_tag, - call_id = message.call_id, - cseq = message.cseq; - - if (!message.to_tag) { - if (message.method === SIP.C.INVITE) { - tr = ua.transactions.ist[message.via_branch]; - if (tr) { - return; - } else { - for (idx in ua.transactions.ist) { - tr = ua.transactions.ist[idx]; - if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) { - reply(482, message, transport); - return false; - } - } - } - } else { - tr = ua.transactions.nist[message.via_branch]; - if (tr) { - return; - } else { - for (idx in ua.transactions.nist) { - tr = ua.transactions.nist[idx]; - if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) { - reply(482, message, transport); - return false; - } - } - } - } - } - } - - // Sanity Check functions for responses - function rfc3261_8_1_3_3(message, ua) { - if (message.getHeaders('via').length > 1) { - ua.getLogger('sip.sanitycheck').warn('More than one Via header field present in the response. Dropping the response'); - return false; - } - } - - function rfc3261_18_1_2(message, ua) { - var viaHost = ua.configuration.viaHost; - if (message.via.host !== viaHost || message.via.port !== undefined) { - ua.getLogger('sip.sanitycheck').warn('Via sent-by in the response does not match UA Via host value. Dropping the response'); - return false; - } - } - - function rfc3261_18_3_response(message, ua) { - var len = SIP.Utils.str_utf8_length(message.body), - contentLength = message.getHeader('content-length'); - - if (len < contentLength) { - ua.getLogger('sip.sanitycheck').warn('Message body length is lower than the value in Content-Length header field. Dropping the response'); - return false; - } - } - - // Sanity Check functions for requests and responses - function minimumHeaders(message, ua) { - var mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via'], - idx = mandatoryHeaders.length; - - while (idx--) { - if (!message.hasHeader(mandatoryHeaders[idx])) { - ua.getLogger('sip.sanitycheck').warn('Missing mandatory header field : ' + mandatoryHeaders[idx] + '. Dropping the response'); - return false; - } - } - } - - requests.push(rfc3261_8_2_2_1); - requests.push(rfc3261_16_3_4); - requests.push(rfc3261_18_3_request); - requests.push(rfc3261_8_2_2_2); - - responses.push(rfc3261_8_1_3_3); - responses.push(rfc3261_18_1_2); - responses.push(rfc3261_18_3_response); - - all.push(minimumHeaders); - - sanityCheck = function sanityCheck(message, ua, transport) { - var len, pass; - - len = all.length; - while (len--) { - pass = all[len](message, ua, transport); - if (pass === false) { - return false; - } - } - - if (message instanceof SIP.IncomingRequest) { - len = requests.length; - while (len--) { - pass = requests[len](message, ua, transport); - if (pass === false) { - return false; - } - } - } else if (message instanceof SIP.IncomingResponse) { - len = responses.length; - while (len--) { - pass = responses[len](message, ua, transport); - if (pass === false) { - return false; - } - } - } - - //Everything is OK - return true; - }; - - SIP.sanityCheck = sanityCheck; -}; - -/***/ }), -/* 29 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * @fileoverview SIP Digest Authentication - */ - -/** - * SIP Digest Authentication. - * @augments SIP. - * @function Digest Authentication - * @param {SIP.UA} ua - */ - -module.exports = function (Utils) { - var DigestAuthentication; - - DigestAuthentication = function DigestAuthentication(ua) { - this.logger = ua.getLogger('sipjs.digestauthentication'); - this.username = ua.configuration.authorizationUser; - this.password = ua.configuration.password; - this.cnonce = null; - this.nc = 0; - this.ncHex = '00000000'; - this.response = null; - }; - - /** - * Performs Digest authentication given a SIP request and the challenge - * received in a response to that request. - * Returns true if credentials were successfully generated, false otherwise. - * - * @param {SIP.OutgoingRequest} request - * @param {Object} challenge - */ - DigestAuthentication.prototype.authenticate = function (request, challenge) { - // Inspect and validate the challenge. - - this.algorithm = challenge.algorithm; - this.realm = challenge.realm; - this.nonce = challenge.nonce; - this.opaque = challenge.opaque; - this.stale = challenge.stale; - - if (this.algorithm) { - if (this.algorithm !== 'MD5') { - this.logger.warn('challenge with Digest algorithm different than "MD5", authentication aborted'); - return false; - } - } else { - this.algorithm = 'MD5'; - } - - if (!this.realm) { - this.logger.warn('challenge without Digest realm, authentication aborted'); - return false; - } - - if (!this.nonce) { - this.logger.warn('challenge without Digest nonce, authentication aborted'); - return false; - } - - // 'qop' can contain a list of values (Array). Let's choose just one. - if (challenge.qop) { - if (challenge.qop.indexOf('auth') > -1) { - this.qop = 'auth'; - } else if (challenge.qop.indexOf('auth-int') > -1) { - this.qop = 'auth-int'; - } else { - // Otherwise 'qop' is present but does not contain 'auth' or 'auth-int', so abort here. - this.logger.warn('challenge without Digest qop different than "auth" or "auth-int", authentication aborted'); - return false; - } - } else { - this.qop = null; - } - - // Fill other attributes. - - this.method = request.method; - this.uri = request.ruri; - this.cnonce = Utils.createRandomToken(12); - this.nc += 1; - this.updateNcHex(); - - // nc-value = 8LHEX. Max value = 'FFFFFFFF'. - if (this.nc === 4294967296) { - this.nc = 1; - this.ncHex = '00000001'; - } - - // Calculate the Digest "response" value. - this.calculateResponse(); - - return true; - }; - - /** - * Generate Digest 'response' value. - * @private - */ - DigestAuthentication.prototype.calculateResponse = function () { - var ha1, ha2; - - // HA1 = MD5(A1) = MD5(username:realm:password) - ha1 = Utils.calculateMD5(this.username + ":" + this.realm + ":" + this.password); - - if (this.qop === 'auth') { - // HA2 = MD5(A2) = MD5(method:digestURI) - ha2 = Utils.calculateMD5(this.method + ":" + this.uri); - // response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2) - this.response = Utils.calculateMD5(ha1 + ":" + this.nonce + ":" + this.ncHex + ":" + this.cnonce + ":auth:" + ha2); - } else if (this.qop === 'auth-int') { - // HA2 = MD5(A2) = MD5(method:digestURI:MD5(entityBody)) - ha2 = Utils.calculateMD5(this.method + ":" + this.uri + ":" + Utils.calculateMD5(this.body ? this.body : "")); - // response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2) - this.response = Utils.calculateMD5(ha1 + ":" + this.nonce + ":" + this.ncHex + ":" + this.cnonce + ":auth-int:" + ha2); - } else if (this.qop === null) { - // HA2 = MD5(A2) = MD5(method:digestURI) - ha2 = Utils.calculateMD5(this.method + ":" + this.uri); - // response = MD5(HA1:nonce:HA2) - this.response = Utils.calculateMD5(ha1 + ":" + this.nonce + ":" + ha2); - } - }; - - /** - * Return the Proxy-Authorization or WWW-Authorization header value. - */ - DigestAuthentication.prototype.toString = function () { - var auth_params = []; - - if (!this.response) { - throw new Error('response field does not exist, cannot generate Authorization header'); - } - - auth_params.push('algorithm=' + this.algorithm); - auth_params.push('username="' + this.username + '"'); - auth_params.push('realm="' + this.realm + '"'); - auth_params.push('nonce="' + this.nonce + '"'); - auth_params.push('uri="' + this.uri + '"'); - auth_params.push('response="' + this.response + '"'); - if (this.opaque) { - auth_params.push('opaque="' + this.opaque + '"'); - } - if (this.qop) { - auth_params.push('qop=' + this.qop); - auth_params.push('cnonce="' + this.cnonce + '"'); - auth_params.push('nc=' + this.ncHex); - } - - return 'Digest ' + auth_params.join(', '); - }; - - /** - * Generate the 'nc' value as required by Digest in this.ncHex by reading this.nc. - * @private - */ - DigestAuthentication.prototype.updateNcHex = function () { - var hex = Number(this.nc).toString(16); - this.ncHex = '00000000'.substr(0, 8 - hex.length) + hex; - }; - - return DigestAuthentication; -}; - -/***/ }), -/* 30 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var Grammar = __webpack_require__(31); - -module.exports = function (SIP) { - - return { - parse: function parseCustom(input, startRule) { - var options = { startRule: startRule, SIP: SIP }; - try { - Grammar.parse(input, options); - } catch (e) { - options.data = -1; - } - return options.data; - } - }; -}; - -/***/ }), -/* 31 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* - * Generated by PEG.js 0.10.0. - * - * http://pegjs.org/ - */ - - - -function peg$subclass(child, parent) { - function ctor() { this.constructor = child; } - ctor.prototype = parent.prototype; - child.prototype = new ctor(); -} - -function peg$SyntaxError(message, expected, found, location) { - this.message = message; - this.expected = expected; - this.found = found; - this.location = location; - this.name = "SyntaxError"; - - if (typeof Error.captureStackTrace === "function") { - Error.captureStackTrace(this, peg$SyntaxError); - } -} - -peg$subclass(peg$SyntaxError, Error); - -peg$SyntaxError.buildMessage = function(expected, found) { - var DESCRIBE_EXPECTATION_FNS = { - literal: function(expectation) { - return "\"" + literalEscape(expectation.text) + "\""; - }, - - "class": function(expectation) { - var escapedParts = "", - i; - - for (i = 0; i < expectation.parts.length; i++) { - escapedParts += expectation.parts[i] instanceof Array - ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1]) - : classEscape(expectation.parts[i]); - } - - return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]"; - }, - - any: function(expectation) { - return "any character"; - }, - - end: function(expectation) { - return "end of input"; - }, - - other: function(expectation) { - return expectation.description; - } - }; - - function hex(ch) { - return ch.charCodeAt(0).toString(16).toUpperCase(); - } - - function literalEscape(s) { - return s - .replace(/\\/g, '\\\\') - .replace(/"/g, '\\"') - .replace(/\0/g, '\\0') - .replace(/\t/g, '\\t') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) - .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); - } - - function classEscape(s) { - return s - .replace(/\\/g, '\\\\') - .replace(/\]/g, '\\]') - .replace(/\^/g, '\\^') - .replace(/-/g, '\\-') - .replace(/\0/g, '\\0') - .replace(/\t/g, '\\t') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) - .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); }); - } - - function describeExpectation(expectation) { - return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); - } - - function describeExpected(expected) { - var descriptions = new Array(expected.length), - i, j; - - for (i = 0; i < expected.length; i++) { - descriptions[i] = describeExpectation(expected[i]); - } - - descriptions.sort(); - - if (descriptions.length > 0) { - for (i = 1, j = 1; i < descriptions.length; i++) { - if (descriptions[i - 1] !== descriptions[i]) { - descriptions[j] = descriptions[i]; - j++; - } - } - descriptions.length = j; - } - - switch (descriptions.length) { - case 1: - return descriptions[0]; - - case 2: - return descriptions[0] + " or " + descriptions[1]; - - default: - return descriptions.slice(0, -1).join(", ") - + ", or " - + descriptions[descriptions.length - 1]; - } - } - - function describeFound(found) { - return found ? "\"" + literalEscape(found) + "\"" : "end of input"; - } - - return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; -}; - -function peg$parse(input, options) { - options = options !== void 0 ? options : {}; - - var peg$FAILED = {}, - - peg$startRuleIndices = { Contact: 118, Name_Addr_Header: 155, Record_Route: 175, Request_Response: 81, SIP_URI: 45, Subscription_State: 185, Supported: 190, Require: 181, Via: 193, absoluteURI: 84, Call_ID: 117, Content_Disposition: 129, Content_Length: 134, Content_Type: 135, CSeq: 145, displayName: 121, Event: 148, From: 150, host: 52, Max_Forwards: 153, Min_SE: 212, Proxy_Authenticate: 156, quoted_string: 40, Refer_To: 177, Replaces: 178, Session_Expires: 209, stun_URI: 216, To: 191, turn_URI: 222, uuid: 225, WWW_Authenticate: 208, challenge: 157, sipfrag: 229, Referred_By: 230 }, - peg$startRuleIndex = 118, - - peg$consts = [ - "\r\n", - peg$literalExpectation("\r\n", false), - /^[0-9]/, - peg$classExpectation([["0", "9"]], false, false), - /^[a-zA-Z]/, - peg$classExpectation([["a", "z"], ["A", "Z"]], false, false), - /^[0-9a-fA-F]/, - peg$classExpectation([["0", "9"], ["a", "f"], ["A", "F"]], false, false), - /^[\0-\xFF]/, - peg$classExpectation([["\0", "\xFF"]], false, false), - /^["]/, - peg$classExpectation(["\""], false, false), - " ", - peg$literalExpectation(" ", false), - "\t", - peg$literalExpectation("\t", false), - /^[a-zA-Z0-9]/, - peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false), - ";", - peg$literalExpectation(";", false), - "/", - peg$literalExpectation("/", false), - "?", - peg$literalExpectation("?", false), - ":", - peg$literalExpectation(":", false), - "@", - peg$literalExpectation("@", false), - "&", - peg$literalExpectation("&", false), - "=", - peg$literalExpectation("=", false), - "+", - peg$literalExpectation("+", false), - "$", - peg$literalExpectation("$", false), - ",", - peg$literalExpectation(",", false), - "-", - peg$literalExpectation("-", false), - "_", - peg$literalExpectation("_", false), - ".", - peg$literalExpectation(".", false), - "!", - peg$literalExpectation("!", false), - "~", - peg$literalExpectation("~", false), - "*", - peg$literalExpectation("*", false), - "'", - peg$literalExpectation("'", false), - "(", - peg$literalExpectation("(", false), - ")", - peg$literalExpectation(")", false), - "%", - peg$literalExpectation("%", false), - function() {return " "; }, - function() {return ':'; }, - /^[!-~]/, - peg$classExpectation([["!", "~"]], false, false), - /^[\x80-\uFFFF]/, - peg$classExpectation([["\x80", "\uFFFF"]], false, false), - /^[\x80-\xBF]/, - peg$classExpectation([["\x80", "\xBF"]], false, false), - /^[a-f]/, - peg$classExpectation([["a", "f"]], false, false), - "`", - peg$literalExpectation("`", false), - "<", - peg$literalExpectation("<", false), - ">", - peg$literalExpectation(">", false), - "\\", - peg$literalExpectation("\\", false), - "[", - peg$literalExpectation("[", false), - "]", - peg$literalExpectation("]", false), - "{", - peg$literalExpectation("{", false), - "}", - peg$literalExpectation("}", false), - function() {return "*"; }, - function() {return "/"; }, - function() {return "="; }, - function() {return "("; }, - function() {return ")"; }, - function() {return ">"; }, - function() {return "<"; }, - function() {return ","; }, - function() {return ";"; }, - function() {return ":"; }, - function() {return "\""; }, - /^[!-']/, - peg$classExpectation([["!", "'"]], false, false), - /^[*-[]/, - peg$classExpectation([["*", "["]], false, false), - /^[\]-~]/, - peg$classExpectation([["]", "~"]], false, false), - function(contents) { - return contents; }, - /^[#-[]/, - peg$classExpectation([["#", "["]], false, false), - /^[\0-\t]/, - peg$classExpectation([["\0", "\t"]], false, false), - /^[\x0B-\f]/, - peg$classExpectation([["\x0B", "\f"]], false, false), - /^[\x0E-\x7F]/, - peg$classExpectation([["\x0E", "\x7F"]], false, false), - function() { - options.data.uri = new options.SIP.URI(options.data.scheme, options.data.user, options.data.host, options.data.port); - delete options.data.scheme; - delete options.data.user; - delete options.data.host; - delete options.data.host_type; - delete options.data.port; - }, - function() { - options.data.uri = new options.SIP.URI(options.data.scheme, options.data.user, options.data.host, options.data.port, options.data.uri_params, options.data.uri_headers); - delete options.data.scheme; - delete options.data.user; - delete options.data.host; - delete options.data.host_type; - delete options.data.port; - delete options.data.uri_params; - - if (options.startRule === 'SIP_URI') { options.data = options.data.uri;} - }, - "sips", - peg$literalExpectation("sips", true), - "sip", - peg$literalExpectation("sip", true), - function(uri_scheme) { - options.data.scheme = uri_scheme; }, - function() { - options.data.user = decodeURIComponent(text().slice(0, -1));}, - function() { - options.data.password = text(); }, - function() { - options.data.host = text(); - return options.data.host; }, - function() { - options.data.host_type = 'domain'; - return text(); }, - /^[a-zA-Z0-9_\-]/, - peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "_", "-"], false, false), - /^[a-zA-Z0-9\-]/, - peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "-"], false, false), - function() { - options.data.host_type = 'IPv6'; - return text(); }, - "::", - peg$literalExpectation("::", false), - function() { - options.data.host_type = 'IPv6'; - return text(); }, - function() { - options.data.host_type = 'IPv4'; - return text(); }, - "25", - peg$literalExpectation("25", false), - /^[0-5]/, - peg$classExpectation([["0", "5"]], false, false), - "2", - peg$literalExpectation("2", false), - /^[0-4]/, - peg$classExpectation([["0", "4"]], false, false), - "1", - peg$literalExpectation("1", false), - /^[1-9]/, - peg$classExpectation([["1", "9"]], false, false), - function(port) { - port = parseInt(port.join('')); - options.data.port = port; - return port; }, - "transport=", - peg$literalExpectation("transport=", true), - "udp", - peg$literalExpectation("udp", true), - "tcp", - peg$literalExpectation("tcp", true), - "sctp", - peg$literalExpectation("sctp", true), - "tls", - peg$literalExpectation("tls", true), - function(transport) { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['transport'] = transport.toLowerCase(); }, - "user=", - peg$literalExpectation("user=", true), - "phone", - peg$literalExpectation("phone", true), - "ip", - peg$literalExpectation("ip", true), - function(user) { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['user'] = user.toLowerCase(); }, - "method=", - peg$literalExpectation("method=", true), - function(method) { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['method'] = method; }, - "ttl=", - peg$literalExpectation("ttl=", true), - function(ttl) { - if(!options.data.params) options.data.params={}; - options.data.params['ttl'] = ttl; }, - "maddr=", - peg$literalExpectation("maddr=", true), - function(maddr) { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['maddr'] = maddr; }, - "lr", - peg$literalExpectation("lr", true), - function() { - if(!options.data.uri_params) options.data.uri_params={}; - options.data.uri_params['lr'] = undefined; }, - function(param, value) { - if(!options.data.uri_params) options.data.uri_params = {}; - if (value === null){ - value = undefined; - } - else { - value = value[1]; - } - options.data.uri_params[param.toLowerCase()] = value && value.toLowerCase();}, - function(hname, hvalue) { - hname = hname.join('').toLowerCase(); - hvalue = hvalue.join(''); - if(!options.data.uri_headers) options.data.uri_headers = {}; - if (!options.data.uri_headers[hname]) { - options.data.uri_headers[hname] = [hvalue]; - } else { - options.data.uri_headers[hname].push(hvalue); - }}, - function() { - // lots of tests fail if this isn't guarded... - if (options.startRule === 'Refer_To') { - options.data.uri = new options.SIP.URI(options.data.scheme, options.data.user, options.data.host, options.data.port, options.data.uri_params, options.data.uri_headers); - delete options.data.scheme; - delete options.data.user; - delete options.data.host; - delete options.data.host_type; - delete options.data.port; - delete options.data.uri_params; - } - }, - "//", - peg$literalExpectation("//", false), - function() { - options.data.scheme= text(); }, - peg$literalExpectation("SIP", true), - function() { - options.data.sip_version = text(); }, - "INVITE", - peg$literalExpectation("INVITE", false), - "ACK", - peg$literalExpectation("ACK", false), - "VXACH", - peg$literalExpectation("VXACH", false), - "OPTIONS", - peg$literalExpectation("OPTIONS", false), - "BYE", - peg$literalExpectation("BYE", false), - "CANCEL", - peg$literalExpectation("CANCEL", false), - "REGISTER", - peg$literalExpectation("REGISTER", false), - "SUBSCRIBE", - peg$literalExpectation("SUBSCRIBE", false), - "NOTIFY", - peg$literalExpectation("NOTIFY", false), - "REFER", - peg$literalExpectation("REFER", false), - function() { - - options.data.method = text(); - return options.data.method; }, - function(status_code) { - options.data.status_code = parseInt(status_code.join('')); }, - function() { - options.data.reason_phrase = text(); }, - function() { - options.data = text(); }, - function() { - var idx, length; - length = options.data.multi_header.length; - for (idx = 0; idx < length; idx++) { - if (options.data.multi_header[idx].parsed === null) { - options.data = null; - break; - } - } - if (options.data !== null) { - options.data = options.data.multi_header; - } else { - options.data = -1; - }}, - function() { - var header; - if(!options.data.multi_header) options.data.multi_header = []; - try { - header = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - delete options.data.uri; - delete options.data.displayName; - delete options.data.params; - } catch(e) { - header = null; - } - options.data.multi_header.push( { 'position': peg$currPos, - 'offset': location().start.offset, - 'parsed': header - });}, - function(displayName) { - displayName = text().trim(); - if (displayName[0] === '\"') { - displayName = displayName.substring(1, displayName.length-1); - } - options.data.displayName = displayName; }, - "q", - peg$literalExpectation("q", true), - function(q) { - if(!options.data.params) options.data.params = {}; - options.data.params['q'] = q; }, - "expires", - peg$literalExpectation("expires", true), - function(expires) { - if(!options.data.params) options.data.params = {}; - options.data.params['expires'] = expires; }, - function(delta_seconds) { - return parseInt(delta_seconds.join('')); }, - "0", - peg$literalExpectation("0", false), - function() { - return parseFloat(text()); }, - function(param, value) { - if(!options.data.params) options.data.params = {}; - if (value === null){ - value = undefined; - } - else { - value = value[1]; - } - options.data.params[param.toLowerCase()] = value;}, - "render", - peg$literalExpectation("render", true), - "session", - peg$literalExpectation("session", true), - "icon", - peg$literalExpectation("icon", true), - "alert", - peg$literalExpectation("alert", true), - function() { - if (options.startRule === 'Content_Disposition') { - options.data.type = text().toLowerCase(); - } - }, - "handling", - peg$literalExpectation("handling", true), - "optional", - peg$literalExpectation("optional", true), - "required", - peg$literalExpectation("required", true), - function(length) { - options.data = parseInt(length.join('')); }, - function() { - options.data = text(); }, - "text", - peg$literalExpectation("text", true), - "image", - peg$literalExpectation("image", true), - "audio", - peg$literalExpectation("audio", true), - "video", - peg$literalExpectation("video", true), - "application", - peg$literalExpectation("application", true), - "message", - peg$literalExpectation("message", true), - "multipart", - peg$literalExpectation("multipart", true), - "x-", - peg$literalExpectation("x-", true), - function(cseq_value) { - options.data.value=parseInt(cseq_value.join('')); }, - function(expires) {options.data = expires; }, - function(event_type) { - options.data.event = event_type.toLowerCase(); }, - function() { - var tag = options.data.tag; - options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - if (tag) {options.data.setParam('tag',tag)} - }, - "tag", - peg$literalExpectation("tag", true), - function(tag) {options.data.tag = tag; }, - function(forwards) { - options.data = parseInt(forwards.join('')); }, - function(min_expires) {options.data = min_expires; }, - function() { - options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - }, - "digest", - peg$literalExpectation("Digest", true), - "realm", - peg$literalExpectation("realm", true), - function(realm) { options.data.realm = realm; }, - "domain", - peg$literalExpectation("domain", true), - "nonce", - peg$literalExpectation("nonce", true), - function(nonce) { options.data.nonce=nonce; }, - "opaque", - peg$literalExpectation("opaque", true), - function(opaque) { options.data.opaque=opaque; }, - "stale", - peg$literalExpectation("stale", true), - "true", - peg$literalExpectation("true", true), - function() { options.data.stale=true; }, - "false", - peg$literalExpectation("false", true), - function() { options.data.stale=false; }, - "algorithm", - peg$literalExpectation("algorithm", true), - "md5", - peg$literalExpectation("MD5", true), - "md5-sess", - peg$literalExpectation("MD5-sess", true), - function(algorithm) { - options.data.algorithm=algorithm.toUpperCase(); }, - "qop", - peg$literalExpectation("qop", true), - "auth-int", - peg$literalExpectation("auth-int", true), - "auth", - peg$literalExpectation("auth", true), - function(qop_value) { - options.data.qop || (options.data.qop=[]); - options.data.qop.push(qop_value.toLowerCase()); }, - function(rack_value) { - options.data.value=parseInt(rack_value.join('')); }, - function() { - var idx, length; - length = options.data.multi_header.length; - for (idx = 0; idx < length; idx++) { - if (options.data.multi_header[idx].parsed === null) { - options.data = null; - break; - } - } - if (options.data !== null) { - options.data = options.data.multi_header; - } else { - options.data = -1; - }}, - function() { - var header; - if(!options.data.multi_header) options.data.multi_header = []; - try { - header = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - delete options.data.uri; - delete options.data.displayName; - delete options.data.params; - } catch(e) { - header = null; - } - options.data.multi_header.push( { 'position': peg$currPos, - 'offset': location().start.offset, - 'parsed': header - });}, - function() { - options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - }, - function() { - if (!(options.data.replaces_from_tag && options.data.replaces_to_tag)) { - options.data = -1; - } - }, - function() { - options.data = { - call_id: options.data - }; - }, - "from-tag", - peg$literalExpectation("from-tag", true), - function(from_tag) { - options.data.replaces_from_tag = from_tag; - }, - "to-tag", - peg$literalExpectation("to-tag", true), - function(to_tag) { - options.data.replaces_to_tag = to_tag; - }, - "early-only", - peg$literalExpectation("early-only", true), - function() { - options.data.early_only = true; - }, - function(head, r) {return r;}, - function(head, tail) { return list(head, tail); }, - function(value) { - if (options.startRule === 'Require') { - options.data = value || []; - } - }, - function(rseq_value) { - options.data.value=parseInt(rseq_value.join('')); }, - "active", - peg$literalExpectation("active", true), - "pending", - peg$literalExpectation("pending", true), - "terminated", - peg$literalExpectation("terminated", true), - function() { - options.data.state = text(); }, - "reason", - peg$literalExpectation("reason", true), - function(reason) { - if (typeof reason !== 'undefined') options.data.reason = reason; }, - function(expires) { - if (typeof expires !== 'undefined') options.data.expires = expires; }, - "retry_after", - peg$literalExpectation("retry_after", true), - function(retry_after) { - if (typeof retry_after !== 'undefined') options.data.retry_after = retry_after; }, - "deactivated", - peg$literalExpectation("deactivated", true), - "probation", - peg$literalExpectation("probation", true), - "rejected", - peg$literalExpectation("rejected", true), - "timeout", - peg$literalExpectation("timeout", true), - "giveup", - peg$literalExpectation("giveup", true), - "noresource", - peg$literalExpectation("noresource", true), - "invariant", - peg$literalExpectation("invariant", true), - function(value) { - if (options.startRule === 'Supported') { - options.data = value || []; - } - }, - function() { - var tag = options.data.tag; - options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params); - if (tag) {options.data.setParam('tag',tag)} - }, - "ttl", - peg$literalExpectation("ttl", true), - function(via_ttl_value) { - options.data.ttl = via_ttl_value; }, - "maddr", - peg$literalExpectation("maddr", true), - function(via_maddr) { - options.data.maddr = via_maddr; }, - "received", - peg$literalExpectation("received", true), - function(via_received) { - options.data.received = via_received; }, - "branch", - peg$literalExpectation("branch", true), - function(via_branch) { - options.data.branch = via_branch; }, - "rport", - peg$literalExpectation("rport", true), - function() { - if(typeof response_port !== 'undefined') - options.data.rport = response_port.join(''); }, - function(via_protocol) { - options.data.protocol = via_protocol; }, - peg$literalExpectation("UDP", true), - peg$literalExpectation("TCP", true), - peg$literalExpectation("TLS", true), - peg$literalExpectation("SCTP", true), - function(via_transport) { - options.data.transport = via_transport; }, - function() { - options.data.host = text(); }, - function(via_sent_by_port) { - options.data.port = parseInt(via_sent_by_port.join('')); }, - function(ttl) { - return parseInt(ttl.join('')); }, - function(deltaSeconds) { - if (options.startRule === 'Session_Expires') { - options.data.deltaSeconds = deltaSeconds; - } - }, - "refresher", - peg$literalExpectation("refresher", false), - "uas", - peg$literalExpectation("uas", false), - "uac", - peg$literalExpectation("uac", false), - function(endpoint) { - if (options.startRule === 'Session_Expires') { - options.data.refresher = endpoint; - } - }, - function(deltaSeconds) { - if (options.startRule === 'Min_SE') { - options.data = deltaSeconds; - } - }, - "stuns", - peg$literalExpectation("stuns", true), - "stun", - peg$literalExpectation("stun", true), - function(scheme) { - options.data.scheme = scheme; }, - function(host) { - options.data.host = host; }, - "?transport=", - peg$literalExpectation("?transport=", false), - "turns", - peg$literalExpectation("turns", true), - "turn", - peg$literalExpectation("turn", true), - function() { - options.data.transport = transport; }, - function() { - options.data = text(); }, - "Referred-By", - peg$literalExpectation("Referred-By", false), - "b", - peg$literalExpectation("b", false), - "cid", - peg$literalExpectation("cid", false) - ], - - peg$bytecode = [ - peg$decode("2 \"\"6 7!"), - peg$decode("4\"\"\"5!7#"), - peg$decode("4$\"\"5!7%"), - peg$decode("4&\"\"5!7'"), - peg$decode(";'.# &;("), - peg$decode("4(\"\"5!7)"), - peg$decode("4*\"\"5!7+"), - peg$decode("2,\"\"6,7-"), - peg$decode("2.\"\"6.7/"), - peg$decode("40\"\"5!71"), - peg$decode("22\"\"6273.\x89 &24\"\"6475.} &26\"\"6677.q &28\"\"6879.e &2:\"\"6:7;.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E"), - peg$decode(";).# &;,"), - peg$decode("2F\"\"6F7G.} &2H\"\"6H7I.q &2J\"\"6J7K.e &2L\"\"6L7M.Y &2N\"\"6N7O.M &2P\"\"6P7Q.A &2R\"\"6R7S.5 &2T\"\"6T7U.) &2V\"\"6V7W"), - peg$decode("%%2X\"\"6X7Y/5#;#/,$;#/#$+#)(#'#(\"'#&'#/\"!&,)"), - peg$decode("%%$;$0#*;$&/,#; /#$+\")(\"'#&'#.\" &\"/=#$;$/�#*;$&&&#/'$8\":Z\" )(\"'#&'#"), - peg$decode(";..\" &\""), - peg$decode("%$;'.# &;(0)*;'.# &;(&/?#28\"\"6879/0$;//'$8#:[# )(#'#(\"'#&'#"), - peg$decode("%%$;2/�#*;2&&&#/g#$%$;.0#*;.&/,#;2/#$+\")(\"'#&'#0=*%$;.0#*;.&/,#;2/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/\"!&,)"), - peg$decode("4\\\"\"5!7].# &;3"), - peg$decode("4^\"\"5!7_"), - peg$decode("4`\"\"5!7a"), - peg$decode(";!.) &4b\"\"5!7c"), - peg$decode("%$;).\x95 &2F\"\"6F7G.\x89 &2J\"\"6J7K.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O/\x9E#0\x9B*;).\x95 &2F\"\"6F7G.\x89 &2J\"\"6J7K.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O&&&#/\"!&,)"), - peg$decode("%$;).\x89 &2F\"\"6F7G.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O/\x92#0\x8F*;).\x89 &2F\"\"6F7G.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O&&&#/\"!&,)"), - peg$decode("2T\"\"6T7U.\xE3 &2V\"\"6V7W.\xD7 &2f\"\"6f7g.\xCB &2h\"\"6h7i.\xBF &2:\"\"6:7;.\xB3 &2D\"\"6D7E.\xA7 &22\"\"6273.\x9B &28\"\"6879.\x8F &2j\"\"6j7k.\x83 &;&.} &24\"\"6475.q &2l\"\"6l7m.e &2n\"\"6n7o.Y &26\"\"6677.M &2>\"\"6>7?.A &2p\"\"6p7q.5 &2r\"\"6r7s.) &;'.# &;("), - peg$decode("%$;).\u012B &2F\"\"6F7G.\u011F &2J\"\"6J7K.\u0113 &2L\"\"6L7M.\u0107 &2X\"\"6X7Y.\xFB &2P\"\"6P7Q.\xEF &2H\"\"6H7I.\xE3 &2@\"\"6@7A.\xD7 &2d\"\"6d7e.\xCB &2R\"\"6R7S.\xBF &2N\"\"6N7O.\xB3 &2T\"\"6T7U.\xA7 &2V\"\"6V7W.\x9B &2f\"\"6f7g.\x8F &2h\"\"6h7i.\x83 &28\"\"6879.w &2j\"\"6j7k.k &;&.e &24\"\"6475.Y &2l\"\"6l7m.M &2n\"\"6n7o.A &26\"\"6677.5 &2p\"\"6p7q.) &2r\"\"6r7s/\u0134#0\u0131*;).\u012B &2F\"\"6F7G.\u011F &2J\"\"6J7K.\u0113 &2L\"\"6L7M.\u0107 &2X\"\"6X7Y.\xFB &2P\"\"6P7Q.\xEF &2H\"\"6H7I.\xE3 &2@\"\"6@7A.\xD7 &2d\"\"6d7e.\xCB &2R\"\"6R7S.\xBF &2N\"\"6N7O.\xB3 &2T\"\"6T7U.\xA7 &2V\"\"6V7W.\x9B &2f\"\"6f7g.\x8F &2h\"\"6h7i.\x83 &28\"\"6879.w &2j\"\"6j7k.k &;&.e &24\"\"6475.Y &2l\"\"6l7m.M &2n\"\"6n7o.A &26\"\"6677.5 &2p\"\"6p7q.) &2r\"\"6r7s&&&#/\"!&,)"), - peg$decode("%;//?#2P\"\"6P7Q/0$;//'$8#:t# )(#'#(\"'#&'#"), - peg$decode("%;//?#24\"\"6475/0$;//'$8#:u# )(#'#(\"'#&'#"), - peg$decode("%;//?#2>\"\"6>7?/0$;//'$8#:v# )(#'#(\"'#&'#"), - peg$decode("%;//?#2T\"\"6T7U/0$;//'$8#:w# )(#'#(\"'#&'#"), - peg$decode("%;//?#2V\"\"6V7W/0$;//'$8#:x# )(#'#(\"'#&'#"), - peg$decode("%2h\"\"6h7i/0#;//'$8\":y\" )(\"'#&'#"), - peg$decode("%;//6#2f\"\"6f7g/'$8\":z\" )(\"'#&'#"), - peg$decode("%;//?#2D\"\"6D7E/0$;//'$8#:{# )(#'#(\"'#&'#"), - peg$decode("%;//?#22\"\"6273/0$;//'$8#:|# )(#'#(\"'#&'#"), - peg$decode("%;//?#28\"\"6879/0$;//'$8#:}# )(#'#(\"'#&'#"), - peg$decode("%;//0#;&/'$8\":~\" )(\"'#&'#"), - peg$decode("%;&/0#;//'$8\":~\" )(\"'#&'#"), - peg$decode("%;=/T#$;G.) &;K.# &;F0/*;G.) &;K.# &;F&/,$;>/#$+#)(#'#(\"'#&'#"), - peg$decode("4\x7F\"\"5!7\x80.A &4\x81\"\"5!7\x82.5 &4\x83\"\"5!7\x84.) &;3.# &;."), - peg$decode("%%;//Q#;&/H$$;J.# &;K0)*;J.# &;K&/,$;&/#$+$)($'#(#'#(\"'#&'#/\"!&,)"), - peg$decode("%;//]#;&/T$%$;J.# &;K0)*;J.# &;K&/\"!&,)/1$;&/($8$:\x85$!!)($'#(#'#(\"'#&'#"), - peg$decode(";..G &2L\"\"6L7M.; &4\x86\"\"5!7\x87./ &4\x83\"\"5!7\x84.# &;3"), - peg$decode("%2j\"\"6j7k/J#4\x88\"\"5!7\x89.5 &4\x8A\"\"5!7\x8B.) &4\x8C\"\"5!7\x8D/#$+\")(\"'#&'#"), - peg$decode("%;N/M#28\"\"6879/>$;O.\" &\"/0$;S/'$8$:\x8E$ )($'#(#'#(\"'#&'#"), - peg$decode("%;N/d#28\"\"6879/U$;O.\" &\"/G$;S/>$;_/5$;l.\" &\"/'$8&:\x8F& )(&'#(%'#($'#(#'#(\"'#&'#"), - peg$decode("%3\x90\"\"5$7\x91.) &3\x92\"\"5#7\x93/' 8!:\x94!! )"), - peg$decode("%;P/]#%28\"\"6879/,#;R/#$+\")(\"'#&'#.\" &\"/6$2:\"\"6:7;/'$8#:\x95# )(#'#(\"'#&'#"), - peg$decode("$;+.) &;-.# &;Q/2#0/*;+.) &;-.# &;Q&&&#"), - peg$decode("2<\"\"6<7=.q &2>\"\"6>7?.e &2@\"\"6@7A.Y &2B\"\"6B7C.M &2D\"\"6D7E.A &22\"\"6273.5 &26\"\"6677.) &24\"\"6475"), - peg$decode("%$;+._ &;-.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E0e*;+._ &;-.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E&/& 8!:\x96! )"), - peg$decode("%;T/J#%28\"\"6879/,#;^/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"), - peg$decode("%;U.) &;\\.# &;X/& 8!:\x97! )"), - peg$decode("%$%;V/2#2J\"\"6J7K/#$+\")(\"'#&'#0<*%;V/2#2J\"\"6J7K/#$+\")(\"'#&'#&/D#;W/;$2J\"\"6J7K.\" &\"/'$8#:\x98# )(#'#(\"'#&'#"), - peg$decode("$4\x99\"\"5!7\x9A/,#0)*4\x99\"\"5!7\x9A&&&#"), - peg$decode("%4$\"\"5!7%/?#$4\x9B\"\"5!7\x9C0)*4\x9B\"\"5!7\x9C&/#$+\")(\"'#&'#"), - peg$decode("%2l\"\"6l7m/?#;Y/6$2n\"\"6n7o/'$8#:\x9D# )(#'#(\"'#&'#"), - peg$decode("%%;Z/\xB3#28\"\"6879/\xA4$;Z/\x9B$28\"\"6879/\x8C$;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+-)(-'#(,'#(+'#(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0790 &%2\x9E\"\"6\x9E7\x9F/\xA4#;Z/\x9B$28\"\"6879/\x8C$;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+,)(,'#(+'#(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u06F9 &%2\x9E\"\"6\x9E7\x9F/\x8C#;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+*)(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u067A &%2\x9E\"\"6\x9E7\x9F/t#;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0613 &%2\x9E\"\"6\x9E7\x9F/\\#;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+&)(&'#(%'#($'#(#'#(\"'#&'#.\u05C4 &%2\x9E\"\"6\x9E7\x9F/D#;Z/;$28\"\"6879/,$;[/#$+$)($'#(#'#(\"'#&'#.\u058D &%2\x9E\"\"6\x9E7\x9F/,#;[/#$+\")(\"'#&'#.\u056E &%2\x9E\"\"6\x9E7\x9F/,#;Z/#$+\")(\"'#&'#.\u054F &%;Z/\x9B#2\x9E\"\"6\x9E7\x9F/\x8C$;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$++)(+'#(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u04C7 &%;Z/\xAA#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x83$2\x9E\"\"6\x9E7\x9F/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+*)(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0430 &%;Z/\xB9#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x92$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/k$2\x9E\"\"6\x9E7\x9F/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+))()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u038A &%;Z/\xC8#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xA1$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/z$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/S$2\x9E\"\"6\x9E7\x9F/D$;Z/;$28\"\"6879/,$;[/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u02D5 &%;Z/\xD7#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xB0$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x89$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/b$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/;$2\x9E\"\"6\x9E7\x9F/,$;[/#$+')(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0211 &%;Z/\xFE#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xD7$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xB0$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x89$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/b$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/;$2\x9E\"\"6\x9E7\x9F/,$;Z/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0126 &%;Z/\u011C#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xF5$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xCE$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xA7$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x80$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/Y$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/2$2\x9E\"\"6\x9E7\x9F/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#/& 8!:\xA0! )"), - peg$decode("%;#/M#;#.\" &\"/?$;#.\" &\"/1$;#.\" &\"/#$+$)($'#(#'#(\"'#&'#"), - peg$decode("%;Z/;#28\"\"6879/,$;Z/#$+#)(#'#(\"'#&'#.# &;\\"), - peg$decode("%;]/o#2J\"\"6J7K/`$;]/W$2J\"\"6J7K/H$;]/?$2J\"\"6J7K/0$;]/'$8':\xA1' )(''#(&'#(%'#($'#(#'#(\"'#&'#"), - peg$decode("%2\xA2\"\"6\xA27\xA3/2#4\xA4\"\"5!7\xA5/#$+\")(\"'#&'#.\x98 &%2\xA6\"\"6\xA67\xA7/;#4\xA8\"\"5!7\xA9/,$;!/#$+#)(#'#(\"'#&'#.j &%2\xAA\"\"6\xAA7\xAB/5#;!/,$;!/#$+#)(#'#(\"'#&'#.B &%4\xAC\"\"5!7\xAD/,#;!/#$+\")(\"'#&'#.# &;!"), - peg$decode("%%;!.\" &\"/[#;!.\" &\"/M$;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+%)(%'#($'#(#'#(\"'#&'#/' 8!:\xAE!! )"), - peg$decode("$%22\"\"6273/,#;`/#$+\")(\"'#&'#0<*%22\"\"6273/,#;`/#$+\")(\"'#&'#&"), - peg$decode(";a.A &;b.; &;c.5 &;d./ &;e.) &;f.# &;g"), - peg$decode("%3\xAF\"\"5*7\xB0/a#3\xB1\"\"5#7\xB2.G &3\xB3\"\"5#7\xB4.; &3\xB5\"\"5$7\xB6./ &3\xB7\"\"5#7\xB8.# &;6/($8\":\xB9\"! )(\"'#&'#"), - peg$decode("%3\xBA\"\"5%7\xBB/I#3\xBC\"\"5%7\xBD./ &3\xBE\"\"5\"7\xBF.# &;6/($8\":\xC0\"! )(\"'#&'#"), - peg$decode("%3\xC1\"\"5'7\xC2/1#;\x8F/($8\":\xC3\"! )(\"'#&'#"), - peg$decode("%3\xC4\"\"5$7\xC5/1#;\xEF/($8\":\xC6\"! )(\"'#&'#"), - peg$decode("%3\xC7\"\"5&7\xC8/1#;T/($8\":\xC9\"! )(\"'#&'#"), - peg$decode("%3\xCA\"\"5\"7\xCB/N#%2>\"\"6>7?/,#;6/#$+\")(\"'#&'#.\" &\"/'$8\":\xCC\" )(\"'#&'#"), - peg$decode("%;h/P#%2>\"\"6>7?/,#;i/#$+\")(\"'#&'#.\" &\"/)$8\":\xCD\"\"! )(\"'#&'#"), - peg$decode("%$;j/�#*;j&&&#/\"!&,)"), - peg$decode("%$;j/�#*;j&&&#/\"!&,)"), - peg$decode(";k.) &;+.# &;-"), - peg$decode("2l\"\"6l7m.e &2n\"\"6n7o.Y &24\"\"6475.M &28\"\"6879.A &2<\"\"6<7=.5 &2@\"\"6@7A.) &2B\"\"6B7C"), - peg$decode("%26\"\"6677/n#;m/e$$%2<\"\"6<7=/,#;m/#$+\")(\"'#&'#0<*%2<\"\"6<7=/,#;m/#$+\")(\"'#&'#&/#$+#)(#'#(\"'#&'#"), - peg$decode("%;n/A#2>\"\"6>7?/2$;o/)$8#:\xCE#\"\" )(#'#(\"'#&'#"), - peg$decode("$;p.) &;+.# &;-/2#0/*;p.) &;+.# &;-&&&#"), - peg$decode("$;p.) &;+.# &;-0/*;p.) &;+.# &;-&"), - peg$decode("2l\"\"6l7m.e &2n\"\"6n7o.Y &24\"\"6475.M &26\"\"6677.A &28\"\"6879.5 &2@\"\"6@7A.) &2B\"\"6B7C"), - peg$decode(";\x90.# &;r"), - peg$decode("%;\x8F/G#;'/>$;s/5$;'/,$;\x84/#$+%)(%'#($'#(#'#(\"'#&'#"), - peg$decode(";M.# &;t"), - peg$decode("%;\x7F/E#28\"\"6879/6$;u.# &;x/'$8#:\xCF# )(#'#(\"'#&'#"), - peg$decode("%;v.# &;w/J#%26\"\"6677/,#;\x83/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"), - peg$decode("%2\xD0\"\"6\xD07\xD1/:#;\x80/1$;w.\" &\"/#$+#)(#'#(\"'#&'#"), - peg$decode("%24\"\"6475/,#;{/#$+\")(\"'#&'#"), - peg$decode("%;z/3#$;y0#*;y&/#$+\")(\"'#&'#"), - peg$decode(";*.) &;+.# &;-"), - peg$decode(";+.\x8F &;-.\x89 &22\"\"6273.} &26\"\"6677.q &28\"\"6879.e &2:\"\"6:7;.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E"), - peg$decode("%;|/e#$%24\"\"6475/,#;|/#$+\")(\"'#&'#0<*%24\"\"6475/,#;|/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"), - peg$decode("%$;~0#*;~&/e#$%22\"\"6273/,#;}/#$+\")(\"'#&'#0<*%22\"\"6273/,#;}/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"), - peg$decode("$;~0#*;~&"), - peg$decode(";+.w &;-.q &28\"\"6879.e &2:\"\"6:7;.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E"), - peg$decode("%%;\"/\x87#$;\".G &;!.A &2@\"\"6@7A.5 &2F\"\"6F7G.) &2J\"\"6J7K0M*;\".G &;!.A &2@\"\"6@7A.5 &2F\"\"6F7G.) &2J\"\"6J7K&/#$+\")(\"'#&'#/& 8!:\xD2! )"), - peg$decode(";\x81.# &;\x82"), - peg$decode("%%;O/2#2:\"\"6:7;/#$+\")(\"'#&'#.\" &\"/,#;S/#$+\")(\"'#&'#.\" &\""), - peg$decode("$;+.\x83 &;-.} &2B\"\"6B7C.q &2D\"\"6D7E.e &22\"\"6273.Y &28\"\"6879.M &2:\"\"6:7;.A &2<\"\"6<7=.5 &2>\"\"6>7?.) &2@\"\"6@7A/\x8C#0\x89*;+.\x83 &;-.} &2B\"\"6B7C.q &2D\"\"6D7E.e &22\"\"6273.Y &28\"\"6879.M &2:\"\"6:7;.A &2<\"\"6<7=.5 &2>\"\"6>7?.) &2@\"\"6@7A&&&#"), - peg$decode("$;y0#*;y&"), - peg$decode("%3\x92\"\"5#7\xD3/q#24\"\"6475/b$$;!/�#*;!&&&#/L$2J\"\"6J7K/=$$;!/�#*;!&&&#/'$8%:\xD4% )(%'#($'#(#'#(\"'#&'#"), - peg$decode("2\xD5\"\"6\xD57\xD6"), - peg$decode("2\xD7\"\"6\xD77\xD8"), - peg$decode("2\xD9\"\"6\xD97\xDA"), - peg$decode("2\xDB\"\"6\xDB7\xDC"), - peg$decode("2\xDD\"\"6\xDD7\xDE"), - peg$decode("2\xDF\"\"6\xDF7\xE0"), - peg$decode("2\xE1\"\"6\xE17\xE2"), - peg$decode("2\xE3\"\"6\xE37\xE4"), - peg$decode("2\xE5\"\"6\xE57\xE6"), - peg$decode("2\xE7\"\"6\xE77\xE8"), - peg$decode("%;\x85.S &;\x86.M &;\x88.G &;\x89.A &;\x8A.; &;\x8B.5 &;\x8C./ &;\x8D.) &;\x8E.# &;6/& 8!:\xE9! )"), - peg$decode("%;\x84/G#;'/>$;\x91/5$;'/,$;\x93/#$+%)(%'#($'#(#'#(\"'#&'#"), - peg$decode("%;\x92/' 8!:\xEA!! )"), - peg$decode("%;!/5#;!/,$;!/#$+#)(#'#(\"'#&'#"), - peg$decode("%$;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(0G*;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(&/& 8!:\xEB! )"), - peg$decode("%;\xB5/Y#$%;A/,#;\xB5/#$+\")(\"'#&'#06*%;A/,#;\xB5/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"), - peg$decode("%;9/N#%2:\"\"6:7;/,#;9/#$+\")(\"'#&'#.\" &\"/'$8\":\xEC\" )(\"'#&'#"), - peg$decode("%;:.c &%;\x97/Y#$%;A/,#;\x97/#$+\")(\"'#&'#06*%;A/,#;\x97/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/& 8!:\xED! )"), - peg$decode("%;L.# &;\x98/]#$%;B/,#;\x9A/#$+\")(\"'#&'#06*%;B/,#;\x9A/#$+\")(\"'#&'#&/'$8\":\xEE\" )(\"'#&'#"), - peg$decode("%;\x99.\" &\"/>#;@/5$;M/,$;?/#$+$)($'#(#'#(\"'#&'#"), - peg$decode("%%;6/Y#$%;./,#;6/#$+\")(\"'#&'#06*%;./,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#.# &;H/' 8!:\xEF!! )"), - peg$decode(";\x9B.) &;\x9C.# &;\x9F"), - peg$decode("%3\xF0\"\"5!7\xF1/:#;$;\xCE/5$;./,$;\x8F/#$+%)(%'#($'#(#'#(\"'#&'#"), - peg$decode("%$;!/�#*;!&&&#/' 8!:\u0149!! )"), - peg$decode("%;\xD0/]#$%;A/,#;\xD0/#$+\")(\"'#&'#06*%;A/,#;\xD0/#$+\")(\"'#&'#&/'$8\":\u014A\" )(\"'#&'#"), - peg$decode("%;\x98/]#$%;B/,#;\x9F/#$+\")(\"'#&'#06*%;B/,#;\x9F/#$+\")(\"'#&'#&/'$8\":\u014B\" )(\"'#&'#"), - peg$decode("%;L.O &;\x98.I &%;@.\" &\"/:#;t/1$;?.\" &\"/#$+#)(#'#(\"'#&'#/]#$%;B/,#;\x9F/#$+\")(\"'#&'#06*%;B/,#;\x9F/#$+\")(\"'#&'#&/'$8\":\u014C\" )(\"'#&'#"), - peg$decode("%;\xD3/]#$%;B/,#;\xD4/#$+\")(\"'#&'#06*%;B/,#;\xD4/#$+\")(\"'#&'#&/'$8\":\u014D\" )(\"'#&'#"), - peg$decode("%;\x95/& 8!:\u014E! )"), - peg$decode("%3\u014F\"\"5(7\u0150/:#;$;6/5$;;/,$;\xEB/#$+%)(%'#($'#(#'#(\"'#&'#"), - peg$decode("%3\x92\"\"5#7\xD3.# &;6/' 8!:\u0189!! )"), - peg$decode("%3\xB1\"\"5#7\u018A.G &3\xB3\"\"5#7\u018B.; &3\xB7\"\"5#7\u018C./ &3\xB5\"\"5$7\u018D.# &;6/' 8!:\u018E!! )"), - peg$decode("%;\xED/D#%;C/,#;\xEE/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"), - peg$decode("%;U.) &;\\.# &;X/& 8!:\u018F! )"), - peg$decode("%%;!.\" &\"/[#;!.\" &\"/M$;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+%)(%'#($'#(#'#(\"'#&'#/' 8!:\u0190!! )"), - peg$decode("%%;!/?#;!.\" &\"/1$;!.\" &\"/#$+#)(#'#(\"'#&'#/' 8!:\u0191!! )"), - peg$decode(";\xBD"), - peg$decode("%;\x9D/^#$%;B/,#;\xF2/#$+\")(\"'#&'#06*%;B/,#;\xF2/#$+\")(\"'#&'#&/($8\":\u0192\"!!)(\"'#&'#"), - peg$decode(";\xF3.# &;\x9F"), - peg$decode("%2\u0193\"\"6\u01937\u0194/L#;\"\"6>7?"), - peg$decode("%;\xFF/b#28\"\"6879/S$;\xFA/J$%2\u01A1\"\"6\u01A17\u01A2/,#;\xEB/#$+\")(\"'#&'#.\" &\"/#$+$)($'#(#'#(\"'#&'#"), - peg$decode("%3\u01A3\"\"5%7\u01A4.) &3\u01A5\"\"5$7\u01A6/' 8!:\u019F!! )"), - peg$decode("%;\xEB/O#3\xB1\"\"5#7\xB2.6 &3\xB3\"\"5#7\xB4.* &$;+0#*;+&/'$8\":\u01A7\" )(\"'#&'#"), - peg$decode("%;\u0103/\x87#2F\"\"6F7G/x$;\u0102/o$2F\"\"6F7G/`$;\u0102/W$2F\"\"6F7G/H$;\u0102/?$2F\"\"6F7G/0$;\u0104/'$8):\u01A8) )()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#"), - peg$decode("%;#/>#;#/5$;#/,$;#/#$+$)($'#(#'#(\"'#&'#"), - peg$decode("%;\u0102/,#;\u0102/#$+\")(\"'#&'#"), - peg$decode("%;\u0102/5#;\u0102/,$;\u0102/#$+#)(#'#(\"'#&'#"), - peg$decode("%;\x84/U#;'/L$;\x91/C$;'/:$;\x8F/1$; .\" &\"/#$+&)(&'#(%'#($'#(#'#(\"'#&'#"), - peg$decode("%2\u01A9\"\"6\u01A97\u01AA.) &2\u01AB\"\"6\u01AB7\u01AC/w#;0/n$;\u0107/e$$%;B/2#;\u0108.# &;\x9F/#$+\")(\"'#&'#0<*%;B/2#;\u0108.# &;\x9F/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"), - peg$decode(";\x98.# &;L"), - peg$decode("%2\u01AD\"\"6\u01AD7\u01AE/5#; peg$maxFailPos) { - peg$maxFailPos = peg$currPos; - peg$maxFailExpected = []; - } - - peg$maxFailExpected.push(expected); - } - - function peg$buildSimpleError(message, location) { - return new peg$SyntaxError(message, null, null, location); - } - - function peg$buildStructuredError(expected, found, location) { - return new peg$SyntaxError( - peg$SyntaxError.buildMessage(expected, found), - expected, - found, - location - ); - } - - function peg$decode(s) { - var bc = new Array(s.length), i; - - for (i = 0; i < s.length; i++) { - bc[i] = s.charCodeAt(i) - 32; - } - - return bc; - } - - function peg$parseRule(index) { - var bc = peg$bytecode[index], - ip = 0, - ips = [], - end = bc.length, - ends = [], - stack = [], - params, i; - - while (true) { - while (ip < end) { - switch (bc[ip]) { - case 0: - stack.push(peg$consts[bc[ip + 1]]); - ip += 2; - break; - - case 1: - stack.push(void 0); - ip++; - break; - - case 2: - stack.push(null); - ip++; - break; - - case 3: - stack.push(peg$FAILED); - ip++; - break; - - case 4: - stack.push([]); - ip++; - break; - - case 5: - stack.push(peg$currPos); - ip++; - break; - - case 6: - stack.pop(); - ip++; - break; - - case 7: - peg$currPos = stack.pop(); - ip++; - break; - - case 8: - stack.length -= bc[ip + 1]; - ip += 2; - break; - - case 9: - stack.splice(-2, 1); - ip++; - break; - - case 10: - stack[stack.length - 2].push(stack.pop()); - ip++; - break; - - case 11: - stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1])); - ip += 2; - break; - - case 12: - stack.push(input.substring(stack.pop(), peg$currPos)); - ip++; - break; - - case 13: - ends.push(end); - ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); - - if (stack[stack.length - 1]) { - end = ip + 3 + bc[ip + 1]; - ip += 3; - } else { - end = ip + 3 + bc[ip + 1] + bc[ip + 2]; - ip += 3 + bc[ip + 1]; - } - - break; - - case 14: - ends.push(end); - ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); - - if (stack[stack.length - 1] === peg$FAILED) { - end = ip + 3 + bc[ip + 1]; - ip += 3; - } else { - end = ip + 3 + bc[ip + 1] + bc[ip + 2]; - ip += 3 + bc[ip + 1]; - } - - break; - - case 15: - ends.push(end); - ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); - - if (stack[stack.length - 1] !== peg$FAILED) { - end = ip + 3 + bc[ip + 1]; - ip += 3; - } else { - end = ip + 3 + bc[ip + 1] + bc[ip + 2]; - ip += 3 + bc[ip + 1]; - } - - break; - - case 16: - if (stack[stack.length - 1] !== peg$FAILED) { - ends.push(end); - ips.push(ip); - - end = ip + 2 + bc[ip + 1]; - ip += 2; - } else { - ip += 2 + bc[ip + 1]; - } - - break; - - case 17: - ends.push(end); - ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]); - - if (input.length > peg$currPos) { - end = ip + 3 + bc[ip + 1]; - ip += 3; - } else { - end = ip + 3 + bc[ip + 1] + bc[ip + 2]; - ip += 3 + bc[ip + 1]; - } - - break; - - case 18: - ends.push(end); - ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]); - - if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]) { - end = ip + 4 + bc[ip + 2]; - ip += 4; - } else { - end = ip + 4 + bc[ip + 2] + bc[ip + 3]; - ip += 4 + bc[ip + 2]; - } - - break; - - case 19: - ends.push(end); - ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]); - - if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]) { - end = ip + 4 + bc[ip + 2]; - ip += 4; - } else { - end = ip + 4 + bc[ip + 2] + bc[ip + 3]; - ip += 4 + bc[ip + 2]; - } - - break; - - case 20: - ends.push(end); - ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]); - - if (peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))) { - end = ip + 4 + bc[ip + 2]; - ip += 4; - } else { - end = ip + 4 + bc[ip + 2] + bc[ip + 3]; - ip += 4 + bc[ip + 2]; - } - - break; - - case 21: - stack.push(input.substr(peg$currPos, bc[ip + 1])); - peg$currPos += bc[ip + 1]; - ip += 2; - break; - - case 22: - stack.push(peg$consts[bc[ip + 1]]); - peg$currPos += peg$consts[bc[ip + 1]].length; - ip += 2; - break; - - case 23: - stack.push(peg$FAILED); - if (peg$silentFails === 0) { - peg$fail(peg$consts[bc[ip + 1]]); - } - ip += 2; - break; - - case 24: - peg$savedPos = stack[stack.length - 1 - bc[ip + 1]]; - ip += 2; - break; - - case 25: - peg$savedPos = peg$currPos; - ip++; - break; - - case 26: - params = bc.slice(ip + 4, ip + 4 + bc[ip + 3]); - for (i = 0; i < bc[ip + 3]; i++) { - params[i] = stack[stack.length - 1 - params[i]]; - } - - stack.splice( - stack.length - bc[ip + 2], - bc[ip + 2], - peg$consts[bc[ip + 1]].apply(null, params) - ); - - ip += 4 + bc[ip + 3]; - break; - - case 27: - stack.push(peg$parseRule(bc[ip + 1])); - ip += 2; - break; - - case 28: - peg$silentFails++; - ip++; - break; - - case 29: - peg$silentFails--; - ip++; - break; - - default: - throw new Error("Invalid opcode: " + bc[ip] + "."); - } - } - - if (ends.length > 0) { - end = ends.pop(); - ip = ips.pop(); - } else { - break; - } - } - - return stack[0]; - } - - - options.data = {}; // Object to which header attributes will be assigned during parsing - - function list (head, tail) { - return [head].concat(tail); - } - - - peg$result = peg$parseRule(peg$startRuleIndex); - - if (peg$result !== peg$FAILED && peg$currPos === input.length) { - return peg$result; - } else { - if (peg$result !== peg$FAILED && peg$currPos < input.length) { - peg$fail(peg$endExpectation()); - } - - throw peg$buildStructuredError( - peg$maxFailExpected, - peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, - peg$maxFailPos < input.length - ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) - : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) - ); - } -} - -module.exports = { - SyntaxError: peg$SyntaxError, - parse: peg$parse -}; - - -/***/ }), -/* 32 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * @name SIP - * @namespace - */ - - -module.exports = function (SIP) { - var Modifiers; - - Modifiers = { - stripTcpCandidates: function stripTcpCandidates(description) { - description.sdp = description.sdp.replace(/^a=candidate:\d+ \d+ tcp .*?\r\n/img, ""); - return SIP.Utils.Promise.resolve(description); - }, - - stripTelephoneEvent: function stripTelephoneEvent(description) { - description.sdp = description.sdp.replace(/^a=rtpmap:\d+ telephone-event\/d+/img, ""); - return SIP.Utils.Promise.resolve(description); - }, - - cleanJitsiSdpImageattr: function cleanJitsiSdpImageattr(description) { - description.sdp = description.sdp.replace(/^(a=imageattr:.*?)(x|y)=\[0-/gm, "$1$2=[1:"); - return SIP.Utils.Promise.resolve(description); - }, - - stripG722: function stripG722(description) { - var parts = description.sdp.match(/^m=audio.*$/gm); - if (parts) { - var mline = parts[0]; - mline = mline.split(" "); - // Ignore the first 3 parameters of the mline. The codec information is after that - for (var i = 3; i < mline.length; i = i + 1) { - if (mline[i] === "9") { - mline.splice(i, 1); - var numberOfCodecs = parseInt(mline[1], 10); - numberOfCodecs = numberOfCodecs - 1; - mline[1] = numberOfCodecs.toString(); - } - } - mline = mline.join(" "); - description.sdp = description.sdp.replace(/^m=audio.*$/gm, mline); - description.sdp = description.sdp.replace(/^a=rtpmap:.*G722\/8000\r\n?/gm, "").replace(); - } - return SIP.Utils.Promise.resolve(description); - } - }; - - return Modifiers; -}; - -/***/ }), -/* 33 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { -/** - * @fileoverview Simple - */ - -/* Simple - * @class Simple - */ - -module.exports = function (SIP) { - - var C = { - STATUS_NULL: 0, - STATUS_NEW: 1, - STATUS_CONNECTING: 2, - STATUS_CONNECTED: 3, - STATUS_COMPLETED: 4 - }; - - /* - * @param {Object} options - */ - var Simple = function Simple(options) { - /* - * { - * media: { - * remote: { - * audio: , - * video: - * }, - * local: { - * video: - * } - * }, - * ua: { - * - * } - * } - */ - - if (options.media.remote.video) { - this.video = true; - } else { - this.video = false; - } - - if (options.media.remote.audio) { - this.audio = true; - } else { - this.audio = false; - } - - if (!this.audio && !this.video) { - // Need to do at least audio or video - // Error - throw new Error('At least one remote audio or video element is required for Simple.'); - } - - this.options = options; - - // https://stackoverflow.com/questions/7944460/detect-safari-browser - var browserUa = global.navigator.userAgent.toLowerCase(); - var isSafari = false; - if (browserUa.indexOf('safari') > -1 && browserUa.indexOf('chrome') < 0) { - isSafari = true; - } - var sessionDescriptionHandlerFactoryOptions = {}; - if (isSafari) { - sessionDescriptionHandlerFactoryOptions.modifiers = [SIP.WebRTC.Modifiers.stripG722]; - } - - if (!this.options.ua.uri) { - this.anonymous = true; - } - - this.ua = new SIP.UA({ - // User Configurable Options - wsServers: this.options.ua.wsServers, - uri: this.options.ua.uri, - authorizationUser: this.options.ua.authorizationUser, - password: this.options.ua.password, - displayName: this.options.ua.displayName, - // Undocumented "Advanced" Options - traceSip: this.options.ua.traceSip, - userAgentString: this.options.ua.userAgentString, - // Fixed Options - register: true, - sessionDescriptionHandlerFactoryOptions: sessionDescriptionHandlerFactoryOptions - }); - - this.state = C.STATUS_NULL; - - this.logger = this.ua.getLogger('sip.simple'); - - this.ua.on('registered', function () { - this.emit('registered', this.ua); - }.bind(this)); - - this.ua.on('unregistered', function () { - this.emit('unregistered', this.ua); - }.bind(this)); - - this.ua.on('failed', function () { - this.emit('unregistered', this.ua); - }.bind(this)); - - this.ua.on('invite', function (session) { - // If there is already an active session reject the incoming session - if (this.state !== C.STATUS_NULL && this.state !== C.STATUS_COMPLETED) { - this.logger.warn('Rejecting incoming call. Simple only supports 1 call at a time'); - session.reject(); - return; - } - this.session = session; - this.setupSession(); - this.emit('ringing', this.session); - }.bind(this)); - - this.ua.on('message', function (message) { - this.emit('message', message); - }.bind(this)); - - return this; - }; - - Simple.prototype = Object.create(SIP.EventEmitter.prototype); - Simple.C = C; - - // Public - - Simple.prototype.call = function (destination) { - if (!this.ua || !this.checkRegistration()) { - this.logger.warn('A registered UA is required for calling'); - return; - } - if (this.state !== C.STATUS_NULL && this.state !== C.STATUS_COMPLETED) { - this.logger.warn('Cannot make more than a single call with Simple'); - return; - } - // Safari hack, because you cannot call .play() from a non user action - if (this.options.media.remote.audio) { - this.options.media.remote.audio.autoplay = true; - } - if (this.options.media.remote.video) { - this.options.media.remote.video.autoplay = true; - } - if (this.options.media.local && this.options.media.local.video) { - this.options.media.local.video.autoplay = true; - this.options.media.local.video.volume = 0; - } - this.session = this.ua.invite(destination, { - sessionDescriptionHandlerOptions: { - constraints: { - audio: this.audio, - video: this.video - } - } - }); - this.setupSession(); - - return this.session; - }; - - Simple.prototype.answer = function () { - if (this.state !== C.STATUS_NEW && this.state !== C.STATUS_CONNECTING) { - this.logger.warn('No call to answer'); - return; - } - // Safari hack, because you cannot call .play() from a non user action - if (this.options.media.remote.audio) { - this.options.media.remote.audio.autoplay = true; - } - if (this.options.media.remote.video) { - this.options.media.remote.video.autoplay = true; - } - return this.session.accept({ - sessionDescriptionHandlerOptions: { - constraints: { - audio: this.audio, - video: this.video - } - } - }); - // emit call is active - }; - - Simple.prototype.reject = function () { - if (this.state !== C.STATUS_NEW && this.state !== C.STATUS_CONNECTING) { - this.logger.warn('Call is already answered'); - return; - } - return this.session.reject(); - }; - - Simple.prototype.hangup = function () { - if (this.state !== C.STATUS_CONNECTED && this.state !== C.STATUS_CONNECTING && this.state !== C.STATUS_NEW) { - this.logger.warn('No active call to hang up on'); - return; - } - if (this.state !== C.STATUS_CONNECTED) { - return this.session.cancel(); - } else { - return this.session.bye(); - } - }; - - Simple.prototype.hold = function () { - if (this.state !== C.STATUS_CONNECTED || this.session.local_hold) { - this.logger.warn('Cannot put call on hold'); - return; - } - this.mute(); - this.logger.log('Placing session on hold'); - return this.session.hold(); - }; - - Simple.prototype.unhold = function () { - if (this.state !== C.STATUS_CONNECTED || !this.session.local_hold) { - this.logger.warn('Cannot unhold a call that is not on hold'); - return; - } - this.unmute(); - this.logger.log('Placing call off hold'); - return this.session.unhold(); - }; - - Simple.prototype.mute = function () { - if (this.state !== C.STATUS_CONNECTED) { - this.logger.warn('An acitve call is required to mute audio'); - return; - } - this.logger.log('Muting Audio'); - this.toggleMute(true); - }; - - Simple.prototype.unmute = function () { - if (this.state !== C.STATUS_CONNECTED) { - this.logger.warn('An active call is required to unmute audio'); - return; - } - this.logger.log('Unmuting Audio'); - this.toggleMute(false); - }; - - Simple.prototype.sendDTMF = function (tone) { - if (this.state !== C.STATUS_CONNECTED) { - this.logger.warn('An active call is required to send a DTMF tone'); - return; - } - this.logger.log('Sending DTMF tone: ' + tone); - this.session.dtmf(tone); - }; - - Simple.prototype.message = function (destination, message) { - if (!this.ua || !this.checkRegistration()) { - this.logger.warn('A registered UA is required to send a message'); - return; - } - if (!destination || !message) { - this.logger.warn('A destination and message are required to send a message'); - return; - } - this.ua.message(destination, message); - }; - - // Private Helpers - - Simple.prototype.checkRegistration = function () { - return this.anonymous || this.ua && this.ua.isRegistered(); - }; - - Simple.prototype.setupRemoteMedia = function () { - // If there is a video track, it will attach the video and audio to the same element - var pc = this.session.sessionDescriptionHandler.peerConnection; - var remoteStream; - - if (pc.getReceivers) { - remoteStream = new global.window.MediaStream(); - pc.getReceivers().forEach(function (receiver) { - var track = receiver.track; - if (track) { - remoteStream.addTrack(track); - } - }); - } else { - remoteStream = pc.getRemoteStreams()[0]; - } - if (this.video) { - this.options.media.remote.video.srcObject = remoteStream; - this.options.media.remote.video.play().catch(function () { - this.logger.log('play was rejected'); - }.bind(this)); - } else if (this.audio) { - this.options.media.remote.audio.srcObject = remoteStream; - this.options.media.remote.audio.play().catch(function () { - this.logger.log('play was rejected'); - }.bind(this)); - } - }; - - Simple.prototype.setupLocalMedia = function () { - if (this.video && this.options.media.local && this.options.media.local.video) { - var pc = this.session.sessionDescriptionHandler.peerConnection; - var localStream; - if (pc.getSenders) { - localStream = new global.window.MediaStream(); - pc.getSenders().forEach(function (sender) { - var track = sender.track; - if (track && track.kind === 'video') { - localStream.addTrack(track); - } - }); - } else { - localStream = pc.getLocalStreams()[0]; - } - this.options.media.local.video.srcObject = localStream; - this.options.media.local.video.volume = 0; - this.options.media.local.video.play(); - } - }; - - Simple.prototype.cleanupMedia = function () { - if (this.video) { - this.options.media.remote.video.srcObject = null; - this.options.media.remote.video.pause(); - if (this.options.media.local && this.options.media.local.video) { - this.options.media.local.video.srcObject = null; - this.options.media.local.video.pause(); - } - } - if (this.audio) { - this.options.media.remote.audio.srcObject = null; - this.options.media.remote.audio.pause(); - } - }; - - Simple.prototype.setupSession = function () { - this.state = C.STATUS_NEW; - this.emit('new', this.session); - - this.session.on('progress', this.onProgress.bind(this)); - this.session.on('accepted', this.onAccepted.bind(this)); - this.session.on('rejected', this.onEnded.bind(this)); - this.session.on('failed', this.onFailed.bind(this)); - this.session.on('terminated', this.onEnded.bind(this)); - }; - - Simple.prototype.destroyMedia = function () { - this.session.sessionDescriptionHandler.close(); - }; - - Simple.prototype.toggleMute = function (mute) { - var pc = this.session.sessionDescriptionHandler.peerConnection; - if (pc.getSenders) { - pc.getSenders().forEach(function (sender) { - if (sender.track) { - sender.track.enabled = !mute; - } - }); - } else { - pc.getLocalStreams().forEach(function (stream) { - stream.getAudioTracks().forEach(function (track) { - track.enabled = !mute; - }); - stream.getVideoTracks().forEach(function (track) { - track.enabled = !mute; - }); - }); - } - }; - - Simple.prototype.onAccepted = function () { - this.state = C.STATUS_CONNECTED; - this.emit('connected', this.session); - - this.setupLocalMedia(); - this.setupRemoteMedia(); - this.session.sessionDescriptionHandler.on('addTrack', function () { - this.logger.log('A track has been added, triggering new remoteMedia setup'); - this.setupRemoteMedia(); - }.bind(this)); - - this.session.sessionDescriptionHandler.on('addStream', function () { - this.logger.log('A stream has been added, trigger new remoteMedia setup'); - this.setupRemoteMedia(); - }.bind(this)); - - this.session.on('hold', function () { - this.emit('hold', this.session); - }.bind(this)); - this.session.on('unhold', function () { - this.emit('unhold', this.session); - }.bind(this)); - this.session.on('dtmf', function (tone) { - this.emit('dtmf', tone); - }.bind(this)); - this.session.on('bye', this.onEnded.bind(this)); - }; - - Simple.prototype.onProgress = function () { - this.state = C.STATUS_CONNECTING; - this.emit('connecting', this.session); - }; - - Simple.prototype.onFailed = function () { - this.onEnded(); - }; - - Simple.prototype.onEnded = function () { - this.state = C.STATUS_COMPLETED; - this.emit('ended', this.session); - this.cleanupMedia(); - }; - - return Simple; -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - -/***/ }), -/* 34 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(global) { - -var toplevel = global.window || global; - -function getPrefixedProperty(object, name) { - if (object == null) { - return; - } - var capitalizedName = name.charAt(0).toUpperCase() + name.slice(1); - var prefixedNames = [name, 'webkit' + capitalizedName, 'moz' + capitalizedName]; - for (var i in prefixedNames) { - var property = object[prefixedNames[i]]; - if (property) { - return property.bind(object); - } - } -} - -module.exports = { - WebSocket: toplevel.WebSocket, - Transport: __webpack_require__(35), - open: toplevel.open, - Promise: toplevel.Promise, - timers: toplevel, - - // Console is not defined in ECMAScript, so just in case... - console: toplevel.console || { - debug: function debug() {}, - log: function log() {}, - warn: function warn() {}, - error: function error() {} - }, - - addEventListener: getPrefixedProperty(toplevel, 'addEventListener'), - removeEventListener: getPrefixedProperty(toplevel, 'removeEventListener') -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) - -/***/ }), -/* 35 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/** - * @fileoverview Transport - */ - -/** - * @augments SIP - * @class Transport - * @param {SIP.UA} ua - * @param {Object} server ws_server Object - */ - -module.exports = function (SIP, WebSocket) { - var Transport, - C = { - // Transport status codes - STATUS_READY: 0, - STATUS_DISCONNECTED: 1, - STATUS_ERROR: 2 - }; - - /** - * Compute an amount of time in seconds to wait before sending another - * keep-alive. - * @returns {Number} - */ - function computeKeepAliveTimeout(upperBound) { - var lowerBound = upperBound * 0.8; - return 1000 * (Math.random() * (upperBound - lowerBound) + lowerBound); - } - - Transport = function Transport(ua, server) { - - this.logger = ua.getLogger('sip.transport'); - this.ua = ua; - this.ws = null; - this.server = server; - this.reconnection_attempts = 0; - this.closed = false; - this.connected = false; - this.reconnectTimer = null; - this.lastTransportError = {}; - - this.keepAliveInterval = ua.configuration.keepAliveInterval; - this.keepAliveTimeout = null; - this.keepAliveTimer = null; - - this.ua.transport = this; - - // Connect - this.connect(); - }; - - Transport.prototype = { - /** - * Send a message. - * @param {SIP.OutgoingRequest|String} msg - * @returns {Boolean} - */ - send: function send(msg) { - var message = msg.toString(); - - if (this.ws && this.ws.readyState === WebSocket.OPEN) { - if (this.ua.configuration.traceSip === true) { - this.logger.log('sending WebSocket message:\n\n' + message + '\n'); - } - this.ws.send(message); - return true; - } else { - this.logger.warn('unable to send message, WebSocket is not open'); - return false; - } - }, - - /** - * Send a keep-alive (a double-CRLF sequence). - * @private - * @returns {Boolean} - */ - sendKeepAlive: function sendKeepAlive() { - if (this.keepAliveTimeout) { - return; - } - - this.keepAliveTimeout = SIP.Timers.setTimeout(function () { - this.ua.emit('keepAliveTimeout'); - }.bind(this), 10000); - - return this.send('\r\n\r\n'); - }, - - /** - * Start sending keep-alives. - * @private - */ - startSendingKeepAlives: function startSendingKeepAlives() { - if (this.keepAliveInterval && !this.keepAliveTimer) { - this.keepAliveTimer = SIP.Timers.setTimeout(function () { - this.sendKeepAlive(); - this.keepAliveTimer = null; - this.startSendingKeepAlives(); - }.bind(this), computeKeepAliveTimeout(this.keepAliveInterval)); - } - }, - - /** - * Stop sending keep-alives. - * @private - */ - stopSendingKeepAlives: function stopSendingKeepAlives() { - SIP.Timers.clearTimeout(this.keepAliveTimer); - SIP.Timers.clearTimeout(this.keepAliveTimeout); - this.keepAliveTimer = null; - this.keepAliveTimeout = null; - }, - - /** - * Disconnect socket. - */ - disconnect: function disconnect() { - if (this.ws) { - // Clear reconnectTimer - SIP.Timers.clearTimeout(this.reconnectTimer); - - this.stopSendingKeepAlives(); - - this.closed = true; - this.logger.log('closing WebSocket ' + this.server.ws_uri); - this.ws.close(); - this.ws = null; - } - - if (this.reconnectTimer !== null) { - SIP.Timers.clearTimeout(this.reconnectTimer); - this.reconnectTimer = null; - this.ua.emit('disconnected', { - transport: this, - code: this.lastTransportError.code, - reason: this.lastTransportError.reason - }); - } - }, - - /** - * Connect socket. - */ - connect: function connect() { - var transport = this; - - if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) { - this.logger.log('WebSocket ' + this.server.ws_uri + ' is already connected'); - return false; - } - - if (this.ws) { - this.ws.close(); - this.ws = null; - } - - this.logger.log('connecting to WebSocket ' + this.server.ws_uri); - this.ua.onTransportConnecting(this, this.reconnection_attempts === 0 ? 1 : this.reconnection_attempts); - - try { - this.ws = new WebSocket(this.server.ws_uri, 'sip'); - } catch (e) { - this.logger.warn('error connecting to WebSocket ' + this.server.ws_uri + ': ' + e); - } - - this.ws.binaryType = 'arraybuffer'; - - this.ws.onopen = function () { - transport.onOpen(); - }; - - this.ws.onclose = function (e) { - transport.onClose(e); - // Always cleanup. Eases GC, prevents potential memory leaks. - this.onopen = null; - this.onclose = null; - this.onmessage = null; - this.onerror = null; - }; - - this.ws.onmessage = function (e) { - transport.onMessage(e); - }; - - this.ws.onerror = function (e) { - transport.onError(e); - }; - }, - - // Transport Event Handlers - - /** - * @event - * @param {event} e - */ - onOpen: function onOpen() { - this.connected = true; - - this.logger.log('WebSocket ' + this.server.ws_uri + ' connected'); - // Clear reconnectTimer since we are not disconnected - if (this.reconnectTimer !== null) { - SIP.Timers.clearTimeout(this.reconnectTimer); - this.reconnectTimer = null; - } - // Reset reconnection_attempts - this.reconnection_attempts = 0; - // Disable closed - this.closed = false; - // Trigger onTransportConnected callback - this.ua.onTransportConnected(this); - // Start sending keep-alives - this.startSendingKeepAlives(); - }, - - /** - * @event - * @param {event} e - */ - onClose: function onClose(e) { - var connected_before = this.connected; - - this.lastTransportError.code = e.code; - this.lastTransportError.reason = e.reason; - - this.stopSendingKeepAlives(); - - if (this.reconnection_attempts > 0) { - this.logger.log('Reconnection attempt ' + this.reconnection_attempts + ' failed (code: ' + e.code + (e.reason ? '| reason: ' + e.reason : '') + ')'); - this.reconnect(); - } else { - this.connected = false; - this.logger.log('WebSocket disconnected (code: ' + e.code + (e.reason ? '| reason: ' + e.reason : '') + ')'); - - if (e.wasClean === false) { - this.logger.warn('WebSocket abrupt disconnection'); - } - // Transport was connected - if (connected_before === true) { - this.ua.onTransportClosed(this); - // Check whether the user requested to close. - if (!this.closed) { - this.reconnect(); - } else { - this.ua.emit('disconnected', { - transport: this, - code: this.lastTransportError.code, - reason: this.lastTransportError.reason - }); - } - } else { - // This is the first connection attempt - //Network error - this.ua.onTransportError(this); - } - } - }, - - /** - * @event - * @param {event} e - */ - onMessage: function onMessage(e) { - var message, - transaction, - data = e.data; - - // CRLF Keep Alive response from server. Ignore it. - if (data === '\r\n') { - SIP.Timers.clearTimeout(this.keepAliveTimeout); - this.keepAliveTimeout = null; - - if (this.ua.configuration.traceSip === true) { - this.logger.log('received WebSocket message with CRLF Keep Alive response'); - } - - return; - } - - // WebSocket binary message. - else if (typeof data !== 'string') { - try { - data = String.fromCharCode.apply(null, new Uint8Array(data)); - } catch (evt) { - this.logger.warn('received WebSocket binary message failed to be converted into string, message discarded'); - return; - } - - if (this.ua.configuration.traceSip === true) { - this.logger.log('received WebSocket binary message:\n\n' + data + '\n'); - } - } - - // WebSocket text message. - else { - if (this.ua.configuration.traceSip === true) { - this.logger.log('received WebSocket text message:\n\n' + data + '\n'); - } - } - - message = SIP.Parser.parseMessage(data, this.ua); - - if (!message) { - return; - } - - if (this.ua.status === SIP.UA.C.STATUS_USER_CLOSED && message instanceof SIP.IncomingRequest) { - return; - } - - // Do some sanity check - if (SIP.sanityCheck(message, this.ua, this)) { - if (message instanceof SIP.IncomingRequest) { - message.transport = this; - this.ua.receiveRequest(message); - } else if (message instanceof SIP.IncomingResponse) { - /* Unike stated in 18.1.2, if a response does not match - * any transaction, it is discarded here and no passed to the core - * in order to be discarded there. - */ - switch (message.method) { - case SIP.C.INVITE: - transaction = this.ua.transactions.ict[message.via_branch]; - if (transaction) { - transaction.receiveResponse(message); - } - break; - case SIP.C.ACK: - // Just in case ;-) - break; - default: - transaction = this.ua.transactions.nict[message.via_branch]; - if (transaction) { - transaction.receiveResponse(message); - } - break; - } - } - } - }, - - /** - * @event - * @param {event} e - */ - onError: function onError(e) { - this.logger.warn('WebSocket connection error: '); - this.logger.warn(e); - }, - - /** - * Reconnection attempt logic. - * @private - */ - reconnect: function reconnect() { - var transport = this; - - this.reconnection_attempts += 1; - - if (this.reconnection_attempts > this.ua.configuration.wsServerMaxReconnection) { - this.logger.warn('maximum reconnection attempts for WebSocket ' + this.server.ws_uri); - this.ua.onTransportError(this); - } else if (this.reconnection_attempts === 1) { - this.logger.log('Connection to WebSocket ' + this.server.ws_uri + ' severed, attempting first reconnect'); - transport.connect(); - } else { - this.logger.log('trying to reconnect to WebSocket ' + this.server.ws_uri + ' (reconnection attempt ' + this.reconnection_attempts + ')'); - - this.reconnectTimer = SIP.Timers.setTimeout(function () { - transport.connect(); - transport.reconnectTimer = null; - }, this.ua.configuration.wsServerReconnectionTimeout * 1000); - } - } - }; - - Transport.C = C; - return Transport; -}; - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/dist/sip.min.js b/dist/sip.min.js deleted file mode 100644 index 4d741f5be..000000000 --- a/dist/sip.min.js +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * - * SIP version 0.9.1 - * Copyright (c) 2014-2017 Junction Networks, Inc - * Homepage: https://sipjs.com - * License: https://sipjs.com/license/ - * - * - * ~~~SIP.js contains substantial portions of JsSIP under the following license~~~ - * Homepage: http://jssip.net - * Copyright (c) 2012-2013 José Luis Millán - Versatica - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * ~~~ end JsSIP license ~~~ - * - * - * - * - */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SIP=t():e.SIP=t()}("undefined"!=typeof self?self:this,function(){return function(e){function t(s){if(i[s])return i[s].exports;var r=i[s]={i:s,l:!1,exports:{}};return e[s].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var i={};return t.m=e,t.c=i,t.d=function(e,i,s){t.o(e,i)||Object.defineProperty(e,i,{configurable:!1,enumerable:!0,get:s})},t.n=function(e){var i=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(i,"a",i),i},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=1)}([function(e,t){var i;i=function(){return this}();try{i=i||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(i=window)}e.exports=i},function(e,t,i){"use strict";e.exports=i(2)(i(34))},function(e,t,i){"use strict";e.exports=function(e){var t=i(3),s=t.version,r=t.title,n=Object.defineProperties({},{version:{get:function(){return s}},name:{get:function(){return r}}});return i(4)(n,e),n.LoggerFactory=i(5)(e.console),n.EventEmitter=i(6)(),n.C=i(8)(n.name,n.version),n.Exceptions=i(9),n.Timers=i(10)(e.timers),n.Transport=e.Transport(n,e.WebSocket),i(11)(n),i(12)(n),i(13)(n),i(14)(n),i(15)(n),i(16)(n),i(18)(n),i(19)(n),n.SessionDescriptionHandler=i(20)(n.EventEmitter),i(21)(n),i(22)(n),i(23)(n),i(25)(n),i(26)(n,e),i(28)(n),n.DigestAuthentication=i(29)(n.Utils),n.Grammar=i(30)(n),n.WebRTC={Modifiers:i(32)(n),Simple:i(33)(n)},n}},function(e,t){e.exports={name:"sip.js",title:"SIP.js",description:"A simple, intuitive, and powerful JavaScript signaling library",version:"0.9.1",main:"dist/sip.min.js",browser:{"./src/environment.js":"./src/environment_browser.js"},homepage:"https://sipjs.com",author:"OnSIP (https://sipjs.com/aboutus/)",contributors:[{url:"https://github.com/onsip/SIP.js/blob/master/THANKS.md"}],repository:{type:"git",url:"https://github.com/onsip/SIP.js.git"},keywords:["sip","websocket","webrtc","library","javascript"],devDependencies:{"babel-core":"^6.26.0","babel-loader":"^7.1.2","babel-preset-env":"^1.6.1",eslint:"^4.9.0","jasmine-core":"^2.8.0",karma:"^1.7.1","karma-cli":"^1.0.1","karma-jasmine":"^1.1.0","karma-jasmine-html-reporter":"^0.2.2","karma-mocha-reporter":"^2.2.5","karma-phantomjs-launcher":"^1.0.4","karma-webpack":"^2.0.6",pegjs:"^0.10.0","pegjs-loader":"^0.5.4","uglifyjs-webpack-plugin":"^1.0.1",webpack:"^3.8.1"},engines:{node:">=4.0"},license:"MIT",scripts:{prebuild:"eslint src/*.js src/**/*.js",build:"webpack --progress && cp dist/sip.js dist/sip-$npm_package_version.js && cp dist/sip.min.js dist/sip-$npm_package_version.min.js",browserTest:"sleep 2 && open http://0.0.0.0:9876/debug.html & karma start --reporters kjhtml --no-single-run",commandLineTest:"karma start --reporters mocha --browsers PhantomJS --single-run",buildAndTest:"npm run build && npm run commandLineTest"},dependencies:{ws:"^1.0.1"},optionalDependencies:{promiscuous:"^0.6.0"}}},function(e,t,i){"use strict";e.exports=function(e,t){var i;i={Promise:t.Promise,defer:function(){var e={};return e.promise=new i.Promise(function(t,i){e.resolve=t,e.reject=i}),e},reducePromises:function(t,i){return t.reduce(function(e,t){return e=e.then(t)},e.Utils.Promise.resolve(i))},augment:function(e,t,i,s){var r,n;n=t.prototype;for(r in n)(s||void 0===e[r])&&(e[r]=n[r]);t.apply(e,i)},optionsOverride:function(e,t,i,s,r,n){s&&e[i]&&r.warn(i+" is deprecated, please use "+t+" instead"),e[t]&&e[i]&&r.warn(t+" overriding "+i),e[t]=e[t]||e[i]||n},str_utf8_length:function(e){return encodeURIComponent(e).replace(/%[A-F\d]{2}/g,"U").length},generateFakeSDP:function(e){if(e){var t=e.indexOf("o="),i=e.indexOf("\r\n",t);return"v=0\r\n"+e.slice(t,i)+"\r\ns=-\r\nt=0 0\r\nc=IN IP4 0.0.0.0"}},isFunction:function(e){return void 0!==e&&"[object Function]"===Object.prototype.toString.call(e)},isDecimal:function(e){return!isNaN(e)&&parseFloat(e)===parseInt(e,10)},createRandomToken:function(e,t){var i,s="";for(t=t||32,i=0;i699)throw new TypeError("Invalid status_code: "+t);if(t)return e.Utils.getReasonHeaderValue(t,i)},buildStatusLine:function(e,t){if(e=e||null,t=t||null,!e||e<100||e>699)throw new TypeError("Invalid status_code: "+e);if(t&&"string"!=typeof t&&!(t instanceof String))throw new TypeError("Invalid reason_phrase: "+t);return t=i.getReasonPhrase(e,t),"SIP/2.0 "+e+" "+t+"\r\n"},getRandomTestNetIP:function(){return"192.0.2."+function(e,t){return Math.floor(Math.random()*(t-e+1)+e)}(1,254)},calculateMD5:function(e){function t(e,t){return e<>>32-t}function i(e,t){var i,s,r,n,o;return r=2147483648&e,n=2147483648&t,i=1073741824&e,s=1073741824&t,o=(1073741823&e)+(1073741823&t),i&s?2147483648^o^r^n:i|s?1073741824&o?3221225472^o^r^n:1073741824^o^r^n:o^r^n}function s(e,s,r,n,o,a,c){return e=i(e,i(i(function(e,t,i){return e&t|~e&i}(s,r,n),o),c)),i(t(e,a),s)}function r(e,s,r,n,o,a,c){return e=i(e,i(i(function(e,t,i){return e&i|t&~i}(s,r,n),o),c)),i(t(e,a),s)}function n(e,s,r,n,o,a,c){return e=i(e,i(i(function(e,t,i){return e^t^i}(s,r,n),o),c)),i(t(e,a),s)}function o(e,s,r,n,o,a,c){return e=i(e,i(i(function(e,t,i){return t^(e|~i)}(s,r,n),o),c)),i(t(e,a),s)}function a(e){var t,i="",s="";for(t=0;t<=3;t++)i+=(s="0"+(e>>>8*t&255).toString(16)).substr(s.length-2,2);return i}var c,h,u,l,d,p,g,f,T,m=[];for(m=function(e){for(var t,i=e.length,s=i+8,r=16*((s-s%64)/64+1),n=Array(r-1),o=0,a=0;a>>29,n}(e=function(e){e=e.replace(/\r\n/g,"\n");for(var t="",i=0;i127&&s<2048?(t+=String.fromCharCode(s>>6|192),t+=String.fromCharCode(63&s|128)):(t+=String.fromCharCode(s>>12|224),t+=String.fromCharCode(s>>6&63|128),t+=String.fromCharCode(63&s|128))}return t}(e)),p=1732584193,g=4023233417,f=2562383102,T=271733878,c=0;c=0&&i<=3?t=i:i>3?t=3:s.hasOwnProperty(i)?t=s[i]:e.error('invalid "level" parameter value: '+JSON.stringify(i))}},connector:{get:function(){return r},set:function(t){null===t||""===t||void 0===t?r=null:"function"==typeof t?r=t:e.error('invalid "connector" parameter value: '+JSON.stringify(t))}}})};return i.prototype.print=function(t,i,s,r){if("string"==typeof r){var n=[new Date,i];s&&n.push(s),r=n.concat(r).join(" | ")}t.call(e,r)},Object.keys(s).forEach(function(r){t.prototype[r]=function(e){this.logger[r](this.category,this.label,e)},i.prototype[r]=function(t,i,n){this.level>=s[r]&&(this.builtinEnabled&&this.print(e[r],t,i,n),this.connector&&this.connector(r,t,i,n))}}),i.prototype.getLogger=function(e,i){var s;return i&&3===this.level?new t(this,e,i):this.loggers[e]?this.loggers[e]:(s=new t(this,e),this.loggers[e]=s,s)},i}},function(e,t,i){"use strict";var s=i(7).EventEmitter;e.exports=function(){function e(){s.call(this)}return e.prototype=Object.create(s.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),e}},function(e,t){function i(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function s(e){return"function"==typeof e}function r(e){return"object"==typeof e&&null!==e}function n(e){return void 0===e}e.exports=i,i.EventEmitter=i,i.prototype._events=void 0,i.prototype._maxListeners=void 0,i.defaultMaxListeners=10,i.prototype.setMaxListeners=function(e){if(!function(e){return"number"==typeof e}(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},i.prototype.emit=function(e){var t,i,o,a,c,h;if(this._events||(this._events={}),"error"===e&&(!this._events.error||r(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var u=new Error('Uncaught, unspecified "error" event. ('+t+")");throw u.context=t,u}if(i=this._events[e],n(i))return!1;if(s(i))switch(arguments.length){case 1:i.call(this);break;case 2:i.call(this,arguments[1]);break;case 3:i.call(this,arguments[1],arguments[2]);break;default:a=Array.prototype.slice.call(arguments,1),i.apply(this,a)}else if(r(i))for(a=Array.prototype.slice.call(arguments,1),o=(h=i.slice()).length,c=0;c0&&this._events[e].length>o&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},i.prototype.on=i.prototype.addListener,i.prototype.once=function(e,t){function i(){this.removeListener(e,i),r||(r=!0,t.apply(this,arguments))}if(!s(t))throw TypeError("listener must be a function");var r=!1;return i.listener=t,this.on(e,i),this},i.prototype.removeListener=function(e,t){var i,n,o,a;if(!s(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(i=this._events[e],o=i.length,n=-1,i===t||s(i.listener)&&i.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(r(i)){for(a=o;a-- >0;)if(i[a]===t||i[a].listener&&i[a].listener===t){n=a;break}if(n<0)return this;1===i.length?(i.length=0,delete this._events[e]):i.splice(n,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},i.prototype.removeAllListeners=function(e){var t,i;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(i=this._events[e],s(i))this.removeListener(e,i);else if(i)for(;i.length;)this.removeListener(e,i[i.length-1]);return delete this._events[e],this},i.prototype.listeners=function(e){return this._events&&this._events[e]?s(this._events[e])?[this._events[e]]:this._events[e].slice():[]},i.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(s(t))return 1;if(t)return t.length}return 0},i.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,i){"use strict";e.exports=function(e,t){return{USER_AGENT:e+"/"+t,SIP:"sip",SIPS:"sips",causes:{CONNECTION_ERROR:"Connection Error",REQUEST_TIMEOUT:"Request Timeout",SIP_FAILURE_CODE:"SIP Failure Code",INTERNAL_ERROR:"Internal Error",BUSY:"Busy",REJECTED:"Rejected",REDIRECTED:"Redirected",UNAVAILABLE:"Unavailable",NOT_FOUND:"Not Found",ADDRESS_INCOMPLETE:"Address Incomplete",INCOMPATIBLE_SDP:"Incompatible SDP",AUTHENTICATION_ERROR:"Authentication Error",DIALOG_ERROR:"Dialog Error",WEBRTC_NOT_SUPPORTED:"WebRTC Not Supported",WEBRTC_ERROR:"WebRTC Error",CANCELED:"Canceled",NO_ANSWER:"No Answer",EXPIRES:"Expires",NO_ACK:"No ACK",NO_PRACK:"No PRACK",USER_DENIED_MEDIA_ACCESS:"User Denied Media Access",BAD_MEDIA_DESCRIPTION:"Bad Media Description",RTP_TIMEOUT:"RTP Timeout"},supported:{UNSUPPORTED:"none",SUPPORTED:"supported",REQUIRED:"required"},SIP_ERROR_CAUSES:{REDIRECTED:[300,301,302,305,380],BUSY:[486,600],REJECTED:[403,603],NOT_FOUND:[404,604],UNAVAILABLE:[480,410,408,430],ADDRESS_INCOMPLETE:[484],INCOMPATIBLE_SDP:[488,606],AUTHENTICATION_ERROR:[401,407]},ACK:"ACK",BYE:"BYE",CANCEL:"CANCEL",INFO:"INFO",INVITE:"INVITE",MESSAGE:"MESSAGE",NOTIFY:"NOTIFY",OPTIONS:"OPTIONS",REGISTER:"REGISTER",UPDATE:"UPDATE",SUBSCRIBE:"SUBSCRIBE",REFER:"REFER",PRACK:"PRACK",REASON_PHRASE:{100:"Trying",180:"Ringing",181:"Call Is Being Forwarded",182:"Queued",183:"Session Progress",199:"Early Dialog Terminated",200:"OK",202:"Accepted",204:"No Notification",300:"Multiple Choices",301:"Moved Permanently",302:"Moved Temporarily",305:"Use Proxy",380:"Alternative Service",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",410:"Gone",412:"Conditional Request Failed",413:"Request Entity Too Large",414:"Request-URI Too Long",415:"Unsupported Media Type",416:"Unsupported URI Scheme",417:"Unknown Resource-Priority",420:"Bad Extension",421:"Extension Required",422:"Session Interval Too Small",423:"Interval Too Brief",428:"Use Identity Header",429:"Provide Referrer Identity",430:"Flow Failed",433:"Anonymity Disallowed",436:"Bad Identity-Info",437:"Unsupported Certificate",438:"Invalid Identity Header",439:"First Hop Lacks Outbound Support",440:"Max-Breadth Exceeded",469:"Bad Info Package",470:"Consent Needed",478:"Unresolvable Destination",480:"Temporarily Unavailable",481:"Call/Transaction Does Not Exist",482:"Loop Detected",483:"Too Many Hops",484:"Address Incomplete",485:"Ambiguous",486:"Busy Here",487:"Request Terminated",488:"Not Acceptable Here",489:"Bad Event",491:"Request Pending",493:"Undecipherable",494:"Security Agreement Required",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Server Time-out",505:"Version Not Supported",513:"Message Too Large",580:"Precondition Failure",600:"Busy Everywhere",603:"Decline",604:"Does Not Exist Anywhere",606:"Not Acceptable"},OPTION_TAGS:{"100rel":!0,199:!0,answermode:!0,"early-session":!0,eventlist:!0,explicitsub:!0,"from-change":!0,"geolocation-http":!0,"geolocation-sip":!0,gin:!0,gruu:!0,histinfo:!0,ice:!0,join:!0,"multiple-refer":!0,norefersub:!0,nosub:!0,outbound:!0,path:!0,policy:!0,precondition:!0,pref:!0,privacy:!0,"recipient-list-invite":!0,"recipient-list-message":!0,"recipient-list-subscribe":!0,replaces:!0,"resource-priority":!0,"sdp-anat":!0,"sec-agree":!0,tdialog:!0,timer:!0,uui:!0}}}},function(e,t,i){"use strict";e.exports={ConfigurationError:function(){var e=function(e,t){this.code=1,this.name="CONFIGURATION_ERROR",this.parameter=e,this.value=t,this.message=this.value?"Invalid value "+JSON.stringify(this.value)+' for parameter "'+this.parameter+'"':"Missing parameter: "+this.parameter};return e.prototype=new Error,e}(),InvalidStateError:function(){var e=function(e){this.code=2,this.name="INVALID_STATE_ERROR",this.status=e,this.message="Invalid status: "+e};return e.prototype=new Error,e}(),NotSupportedError:function(){var e=function(e){this.code=3,this.name="NOT_SUPPORTED_ERROR",this.message=e};return e.prototype=new Error,e}(),GetDescriptionError:function(){var e=function(e){this.code=4,this.name="GET_DESCRIPTION_ERROR",this.message=e};return e.prototype=new Error,e}(),RenegotiationError:function(){var e=function(e){this.code=5,this.name="RENEGOTIATION_ERROR",this.message=e};return e.prototype=new Error,e}()}},function(e,t,i){"use strict";e.exports=function(e){var t={T1:500,T2:4e3,T4:5e3,TIMER_B:32e3,TIMER_D:0,TIMER_F:32e3,TIMER_H:32e3,TIMER_I:0,TIMER_J:0,TIMER_K:0,TIMER_L:32e3,TIMER_M:32e3,TIMER_N:32e3,PROVISIONAL_RESPONSE_INTERVAL:6e4};return["setTimeout","clearTimeout","setInterval","clearInterval"].forEach(function(i){t[i]=function(){return e[i].apply(e,arguments)}}),t}},function(e,t,i){"use strict";e.exports=function(e){function t(e,t){var i=t,s=0,r=0;if(e.substring(i,i+2).match(/(^\r\n)/))return-2;for(;0===s;){if(-1===(r=e.indexOf("\r\n",i)))return r;!e.substring(r+2,r+4).match(/(^\r\n)/)&&e.charAt(r+2).match(/(^\s+)/)?i=r+2:s=r}return s}function i(t,i,s,r){var n,o,a,c,h=i.indexOf(":",s),u=i.substring(s,h).trim(),l=i.substring(h+1,r).trim();switch(u.toLowerCase()){case"via":case"v":t.addHeader("via",l),1===t.getHeaders("via").length?(c=t.parseHeader("Via"))&&(t.via=c,t.via_branch=c.branch):c=0;break;case"from":case"f":t.setHeader("from",l),(c=t.parseHeader("from"))&&(t.from=c,t.from_tag=c.getParam("tag"));break;case"to":case"t":t.setHeader("to",l),(c=t.parseHeader("to"))&&(t.to=c,t.to_tag=c.getParam("tag"));break;case"record-route":if(-1===(c=e.Grammar.parse(l,"Record_Route"))){c=void 0;break}for(a=c.length,o=0;o",a+=r.to_tag?";tag="+r.to_tag:"",this.to=new e.NameAddrHeader.parse(a),this.setHeader("to",a),d=r.from_uri||s.configuration.uri,c=r.from_displayName||0===r.from_displayName?'"'+r.from_displayName+'" ':s.configuration.displayName?'"'+s.configuration.displayName+'" ':"",c+="<"+(d&&d.toRaw?d.toRaw():d)+">;tag=",c+=r.from_tag||e.Utils.newTag(),this.from=new e.NameAddrHeader.parse(c),this.setHeader("from",c),h=r.call_id||s.configuration.sipjsId+e.Utils.createRandomToken(15),this.call_id=h,this.setHeader("call-id",h),u=r.cseq||Math.floor(1e4*Math.random()),this.cseq=u,this.setHeader("cseq",u+" "+t)}).prototype={setHeader:function(t,i){this.headers[e.Utils.headerize(t)]=i instanceof Array?i:[i]},getHeader:function(t){var i,s,r=this.extraHeaders.length,n=this.headers[e.Utils.headerize(t)];if(n){if(n[0])return n[0]}else for(i=new RegExp("^\\s*"+t+"\\s*:","i"),s=0;s=this.headers[t].length))return s=this.headers[t][i],r=s.raw,s.parsed?s.parsed:-1===(n=e.Grammar.parse(r,t.replace(/-/g,"_")))?(this.headers[t].splice(i,1),void this.logger.warn('error parsing "'+t+'" header field with value "'+r+'"')):(s.parsed=n,n);this.logger.log('not so many "'+t+'" headers present')}else this.logger.log('header "'+t+'" not present')},s:function(e,t){return this.parseHeader(e,t)},setHeader:function(t,i){var s={raw:i};this.headers[e.Utils.headerize(t)]=[s]},toString:function(){return this.data}},((r=function(e){this.logger=e.getLogger("sip.sipmessage"),this.ua=e,this.headers={},this.ruri=null,this.transport=null,this.server_transaction=null}).prototype=new s).reply=function(i,s,r,n,o,a){var c,h,u,l,d,p=this.getHeader("To"),g=0,f=0;if(d=e.Utils.buildStatusLine(i,s),r=(r||[]).slice(),this.method===e.C.INVITE&&i>100&&i<=200)for(u=(c=this.getHeaders("record-route")).length;g100?p+=";tag="+e.Utils.newTag():this.to_tag&&!this.s("to").hasParam("tag")&&(p+=";tag="+this.to_tag),d+="To: "+p+"\r\n",d+="From: "+this.getHeader("From")+"\r\n",d+="Call-ID: "+this.call_id+"\r\n",d+="CSeq: "+this.cseq+" "+this.method+"\r\n",u=r.length,l=0;l100?s+=";tag="+e.Utils.newTag():this.to_tag&&!this.s("to").hasParam("tag")&&(s+=";tag="+this.to_tag),r+="To: "+s+"\r\n",r+="From: "+this.getHeader("From")+"\r\n",r+="Call-ID: "+this.call_id+"\r\n",r+="CSeq: "+this.cseq+" "+this.method+"\r\n",r+="User-Agent: "+this.ua.configuration.userAgentString+"\r\n",r+="Content-Length: 0\r\n\r\n",this.transport.send(r)},(n=function(e){this.logger=e.getLogger("sip.sipmessage"),this.headers={},this.status_code=null,this.reason_phrase=null}).prototype=new s,e.OutgoingRequest=i,e.IncomingRequest=r,e.IncomingResponse=n}},function(e,t,i){"use strict";e.exports=function(e){var t;(t=function(t,i,s,r,n,o){var a,c,h,u;if(!s)throw new TypeError('missing or invalid "host" parameter');t=t||e.C.SIP,this.parameters={},this.headers={};for(a in n)this.setParam(a,n[a]);for(c in o)this.setHeader(c,o[c]);h={scheme:t,user:i,host:s,port:r},u={scheme:t.toLowerCase(),user:i,host:s.toLowerCase(),port:r},Object.defineProperties(this,{_normal:{get:function(){return u}},_raw:{get:function(){return h}},scheme:{get:function(){return u.scheme},set:function(e){h.scheme=e,u.scheme=e.toLowerCase()}},user:{get:function(){return u.user},set:function(e){u.user=h.user=e}},host:{get:function(){return u.host},set:function(e){h.host=e,u.host=e.toLowerCase()}},aor:{get:function(){return u.user+"@"+u.host}},port:{get:function(){return u.port},set:function(e){u.port=h.port=0===e?e:parseInt(e,10)||null}}})}).prototype={setParam:function(e,t){e&&(this.parameters[e.toLowerCase()]=void 0===t||null===t?null:t.toString().toLowerCase())},getParam:function(e){if(e)return this.parameters[e.toLowerCase()]},hasParam:function(e){if(e)return!!this.parameters.hasOwnProperty(e.toLowerCase())},deleteParam:function(e){var t;if(e=e.toLowerCase(),this.parameters.hasOwnProperty(e))return t=this.parameters[e],delete this.parameters[e],t},clearParams:function(){this.parameters={}},setHeader:function(t,i){this.headers[e.Utils.headerize(t)]=i instanceof Array?i:[i]},getHeader:function(t){if(t)return this.headers[e.Utils.headerize(t)]},hasHeader:function(t){if(t)return!!this.headers.hasOwnProperty(e.Utils.headerize(t))},deleteHeader:function(t){var i;if(t=e.Utils.headerize(t),this.headers.hasOwnProperty(t))return i=this.headers[t],delete this.headers[t],i},clearHeaders:function(){this.headers={}},clone:function(){return new t(this._raw.scheme,this._raw.user,this._raw.host,this._raw.port,JSON.parse(JSON.stringify(this.parameters)),JSON.parse(JSON.stringify(this.headers)))},toRaw:function(){return this._toString(this._raw)},toString:function(){return this._toString(this._normal)},_toString:function(t){var i,s,r,n,o=[];n=t.scheme+":",t.scheme.toLowerCase().match("^sips?$")||(n+="//"),t.user&&(n+=e.Utils.escapeUser(t.user)+"@"),n+=t.host,(t.port||0===t.port)&&(n+=":"+t.port);for(s in this.parameters)n+=";"+s,null!==this.parameters[s]&&(n+="="+this.parameters[s]);for(i in this.headers)for(r in this.headers[i])o.push(i+"="+this.headers[i][r]);return o.length>0&&(n+="?"+o.join("&")),n}},t.parse=function(t){return-1!==(t=e.Grammar.parse(t,"SIP_URI"))?t:void 0},e.URI=t}},function(e,t,i){"use strict";e.exports=function(e){var t;(t=function(t,i,s){var r;if(!(t&&t instanceof e.URI))throw new TypeError('missing or invalid "uri" parameter');this.uri=t,this.parameters={};for(r in s)this.setParam(r,s[r]);Object.defineProperties(this,{friendlyName:{get:function(){return this.displayName||t.aor}},displayName:{get:function(){return i},set:function(e){i=0===e?"0":e}}})}).prototype={setParam:function(e,t){e&&(this.parameters[e.toLowerCase()]=void 0===t||null===t?null:t.toString())},getParam:e.URI.prototype.getParam,hasParam:e.URI.prototype.hasParam,deleteParam:e.URI.prototype.deleteParam,clearParams:e.URI.prototype.clearParams,clone:function(){return new t(this.uri.clone(),this.displayName,JSON.parse(JSON.stringify(this.parameters)))},toString:function(){var e,t;e=this.displayName||0===this.displayName?'"'+this.displayName+'" ':"",e+="<"+this.uri.toString()+">";for(t in this.parameters)e+=";"+t,null!==this.parameters[t]&&(e+="="+this.parameters[t]);return e}},t.parse=function(t){return-1!==(t=e.Grammar.parse(t,"Name_Addr_Header"))?t:void 0},e.NameAddrHeader=t}},function(e,t,i){"use strict";e.exports=function(e){function t(e,t,i){var s;return s="SIP/2.0/"+(e.ua.configuration.hackViaTcp?"TCP":t.server.scheme),s+=" "+e.ua.configuration.viaHost+";branch="+i,e.ua.configuration.forceRport&&(s+=";rport"),s}var i={STATUS_TRYING:1,STATUS_PROCEEDING:2,STATUS_CALLING:3,STATUS_ACCEPTED:4,STATUS_COMPLETED:5,STATUS_TERMINATED:6,STATUS_CONFIRMED:7,NON_INVITE_CLIENT:"nict",NON_INVITE_SERVER:"nist",INVITE_CLIENT:"ict",INVITE_SERVER:"ist"},s=function(e,s,r){var n;this.type=i.NON_INVITE_CLIENT,this.transport=r,this.id="z9hG4bK"+Math.floor(1e7*Math.random()),this.request_sender=e,this.request=s,this.logger=e.ua.getLogger("sip.transaction.nict",this.id),n=t(e,r,this.id),this.request.setHeader("via",n),this.request_sender.ua.newTransaction(this)};(s.prototype=Object.create(e.EventEmitter.prototype)).stateChanged=function(e){this.state=e,this.emit("stateChanged")},s.prototype.send=function(){this.stateChanged(i.STATUS_TRYING),this.F=e.Timers.setTimeout(this.timer_F.bind(this),e.Timers.TIMER_F),this.transport.send(this.request)||this.onTransportError()},s.prototype.onTransportError=function(){this.logger.log("transport error occurred, deleting non-INVITE client transaction "+this.id),e.Timers.clearTimeout(this.F),e.Timers.clearTimeout(this.K),this.stateChanged(i.STATUS_TERMINATED),this.request_sender.ua.destroyTransaction(this),this.request_sender.onTransportError()},s.prototype.timer_F=function(){this.logger.debug("Timer F expired for non-INVITE client transaction "+this.id),this.stateChanged(i.STATUS_TERMINATED),this.request_sender.ua.destroyTransaction(this),this.request_sender.onRequestTimeout()},s.prototype.timer_K=function(){this.stateChanged(i.STATUS_TERMINATED),this.request_sender.ua.destroyTransaction(this)},s.prototype.receiveResponse=function(t){var s=t.status_code;if(s<200)switch(this.state){case i.STATUS_TRYING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_PROCEEDING),this.request_sender.receiveResponse(t)}else switch(this.state){case i.STATUS_TRYING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_COMPLETED),e.Timers.clearTimeout(this.F),408===s?this.request_sender.onRequestTimeout():this.request_sender.receiveResponse(t),this.K=e.Timers.setTimeout(this.timer_K.bind(this),e.Timers.TIMER_K)}};var r=function(e,s,r){var n,o=this;this.type=i.INVITE_CLIENT,this.transport=r,this.id="z9hG4bK"+Math.floor(1e7*Math.random()),this.request_sender=e,this.request=s,this.logger=e.ua.getLogger("sip.transaction.ict",this.id),n=t(e,r,this.id),this.request.setHeader("via",n),this.request_sender.ua.newTransaction(this),this.request.cancel=function(e,t){for(var i=(t=(t||[]).slice()).length,s=null,r=0;r=100&&s<=199)switch(this.state){case i.STATUS_CALLING:this.stateChanged(i.STATUS_PROCEEDING),this.request_sender.receiveResponse(t),this.cancel&&this.transport.send(this.cancel);break;case i.STATUS_PROCEEDING:this.request_sender.receiveResponse(t)}else if(s>=200&&s<=299)switch(this.state){case i.STATUS_CALLING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_ACCEPTED),this.M=e.Timers.setTimeout(this.timer_M.bind(this),e.Timers.TIMER_M),this.request_sender.receiveResponse(t);break;case i.STATUS_ACCEPTED:this.request_sender.receiveResponse(t)}else if(s>=300&&s<=699)switch(this.state){case i.STATUS_CALLING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_COMPLETED),this.sendACK(),this.request_sender.receiveResponse(t);break;case i.STATUS_COMPLETED:this.sendACK()}};var n=function(e,i,s){var r;this.transport=s,this.id="z9hG4bK"+Math.floor(1e7*Math.random()),this.request_sender=e,this.request=i,this.logger=e.ua.getLogger("sip.transaction.nict",this.id),r=t(e,s,this.id),this.request.setHeader("via",r)};(n.prototype=Object.create(e.EventEmitter.prototype)).send=function(){this.transport.send(this.request)||this.onTransportError()},n.prototype.onTransportError=function(){this.logger.log("transport error occurred, for an ACK client transaction "+this.id),this.request_sender.onTransportError()};var o=function(e,t){this.type=i.NON_INVITE_SERVER,this.id=e.via_branch,this.request=e,this.transport=e.transport,this.ua=t,this.last_response="",e.server_transaction=this,this.logger=t.getLogger("sip.transaction.nist",this.id),this.state=i.STATUS_TRYING,t.newTransaction(this)};(o.prototype=Object.create(e.EventEmitter.prototype)).stateChanged=function(e){this.state=e,this.emit("stateChanged")},o.prototype.timer_J=function(){this.logger.debug("Timer J expired for non-INVITE server transaction "+this.id),this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this)},o.prototype.onTransportError=function(){this.transportError||(this.transportError=!0,this.logger.log("transport error occurred, deleting non-INVITE server transaction "+this.id),e.Timers.clearTimeout(this.J),this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this))},o.prototype.receiveResponse=function(t,s){var r=e.Utils.defer();if(100===t)switch(this.state){case i.STATUS_TRYING:this.stateChanged(i.STATUS_PROCEEDING),this.transport.send(s)||this.onTransportError();break;case i.STATUS_PROCEEDING:this.last_response=s,this.transport.send(s)?r.resolve():(this.onTransportError(),r.reject())}else if(t>=200&&t<=699)switch(this.state){case i.STATUS_TRYING:case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_COMPLETED),this.last_response=s,this.J=e.Timers.setTimeout(this.timer_J.bind(this),e.Timers.TIMER_J),this.transport.send(s)?r.resolve():(this.onTransportError(),r.reject())}return r.promise};var a=function(e,t){this.type=i.INVITE_SERVER,this.id=e.via_branch,this.request=e,this.transport=e.transport,this.ua=t,this.last_response="",e.server_transaction=this,this.logger=t.getLogger("sip.transaction.ist",this.id),this.state=i.STATUS_PROCEEDING,t.newTransaction(this),this.resendProvisionalTimer=null,e.reply(100)};(a.prototype=Object.create(e.EventEmitter.prototype)).stateChanged=function(e){this.state=e,this.emit("stateChanged")},a.prototype.timer_H=function(){this.logger.debug("Timer H expired for INVITE server transaction "+this.id),this.state===i.STATUS_COMPLETED&&this.logger.warn("transactions","ACK for INVITE server transaction was never received, call will be terminated"),this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this)},a.prototype.timer_I=function(){this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this)},a.prototype.timer_L=function(){this.logger.debug("Timer L expired for INVITE server transaction "+this.id),this.state===i.STATUS_ACCEPTED&&(this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this))},a.prototype.onTransportError=function(){this.transportError||(this.transportError=!0,this.logger.log("transport error occurred, deleting INVITE server transaction "+this.id),null!==this.resendProvisionalTimer&&(e.Timers.clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),e.Timers.clearTimeout(this.L),e.Timers.clearTimeout(this.H),e.Timers.clearTimeout(this.I),this.stateChanged(i.STATUS_TERMINATED),this.ua.destroyTransaction(this))},a.prototype.resend_provisional=function(){this.transport.send(this.last_response)||this.onTransportError()},a.prototype.receiveResponse=function(t,s){var r=e.Utils.defer();if(t>=100&&t<=199)switch(this.state){case i.STATUS_PROCEEDING:this.transport.send(s)||this.onTransportError(),this.last_response=s}if(t>100&&t<=199&&this.state===i.STATUS_PROCEEDING)null===this.resendProvisionalTimer&&(this.resendProvisionalTimer=e.Timers.setInterval(this.resend_provisional.bind(this),e.Timers.PROVISIONAL_RESPONSE_INTERVAL));else if(t>=200&&t<=299)switch(this.state){case i.STATUS_PROCEEDING:this.stateChanged(i.STATUS_ACCEPTED),this.last_response=s,this.L=e.Timers.setTimeout(this.timer_L.bind(this),e.Timers.TIMER_L),null!==this.resendProvisionalTimer&&(e.Timers.clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null);case i.STATUS_ACCEPTED:this.transport.send(s)?r.resolve():(this.onTransportError(),r.reject())}else if(t>=300&&t<=699)switch(this.state){case i.STATUS_PROCEEDING:null!==this.resendProvisionalTimer&&(e.Timers.clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),this.transport.send(s)?(this.stateChanged(i.STATUS_COMPLETED),this.H=e.Timers.setTimeout(this.timer_H.bind(this),e.Timers.TIMER_H),r.resolve()):(this.onTransportError(),r.reject())}return r.promise};e.Transactions={C:i,checkTransaction:function(t,s){var r;switch(s.method){case e.C.INVITE:if(r=t.transactions.ist[s.via_branch]){switch(r.state){case i.STATUS_PROCEEDING:r.transport.send(r.last_response)}return!0}break;case e.C.ACK:if(!(r=t.transactions.ist[s.via_branch]))return!1;if(r.state===i.STATUS_ACCEPTED)return!1;if(r.state===i.STATUS_COMPLETED)return r.stateChanged(i.STATUS_CONFIRMED),r.I=e.Timers.setTimeout(r.timer_I.bind(r),e.Timers.TIMER_I),!0;break;case e.C.CANCEL:return(r=t.transactions.ist[s.via_branch])?(s.reply_sl(200),r.state!==i.STATUS_PROCEEDING):(s.reply_sl(481),!0);default:if(r=t.transactions.nist[s.via_branch]){switch(r.state){case i.STATUS_TRYING:break;case i.STATUS_PROCEEDING:case i.STATUS_COMPLETED:r.transport.send(r.last_response)}return!0}}},NonInviteClientTransaction:s,InviteClientTransaction:r,AckClientTransaction:n,NonInviteServerTransaction:o,InviteServerTransaction:a}}},function(e,t,i){"use strict";e.exports=function(e){var t,s=i(17)(e),r={STATUS_EARLY:1,STATUS_CONFIRMED:2};(t=function(t,i,s,n){var o;if(this.uac_pending_reply=!1,this.uas_pending_reply=!1,!i.hasHeader("contact"))return{error:"unable to create a Dialog without Contact header field"};n=i instanceof e.IncomingResponse?i.status_code<200?r.STATUS_EARLY:r.STATUS_CONFIRMED:n||r.STATUS_CONFIRMED,o=i.parseHeader("contact"),"UAS"===s?(this.id={call_id:i.call_id,local_tag:i.to_tag,remote_tag:i.from_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this.state=n,this.remote_seqnum=i.cseq,this.local_uri=i.parseHeader("to").uri,this.remote_uri=i.parseHeader("from").uri,this.remote_target=o.uri,this.route_set=i.getHeaders("record-route"),this.invite_seqnum=i.cseq,this.local_seqnum=i.cseq):"UAC"===s&&(this.id={call_id:i.call_id,local_tag:i.from_tag,remote_tag:i.to_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this.state=n,this.invite_seqnum=i.cseq,this.local_seqnum=i.cseq,this.local_uri=i.parseHeader("from").uri,this.pracked=[],this.remote_uri=i.parseHeader("to").uri,this.remote_target=o.uri,this.route_set=i.getHeaders("record-route").reverse()),this.logger=t.ua.getLogger("sip.dialog",this.id.toString()),this.owner=t,t.ua.dialogs[this.id.toString()]=this,this.logger.log("new "+s+" dialog created with status "+(this.state===r.STATUS_EARLY?"EARLY":"CONFIRMED")),t.emit("dialog",this)}).prototype={update:function(e,t){this.state=r.STATUS_CONFIRMED,this.logger.log("dialog "+this.id.toString()+" changed to CONFIRMED state"),"UAC"===t&&(this.route_set=e.getHeaders("record-route").reverse())},terminate:function(){this.logger.log("dialog "+this.id.toString()+" deleted"),this.sessionDescriptionHandler&&this.state!==r.STATUS_CONFIRMED&&this.sessionDescriptionHandler.close(),delete this.owner.ua.dialogs[this.id.toString()]},createRequest:function(t,i,s){var r,n;return i=(i||[]).slice(),this.local_seqnum||(this.local_seqnum=Math.floor(1e4*Math.random())),r=t===e.C.CANCEL||t===e.C.ACK?this.invite_seqnum:this.local_seqnum+=1,n=new e.OutgoingRequest(t,this.remote_target,this.owner.ua,{cseq:r,call_id:this.id.call_id,from_uri:this.local_uri,from_tag:this.id.local_tag,to_uri:this.remote_uri,to_tag:this.id.remote_tag,route_set:this.route_set},i,s),n.dialog=this,n},checkInDialogRequest:function(t){var i=this;if(this.remote_seqnum){if(t.cseqthis.remote_seqnum){var s=1+(10*Math.random()|0);return t.reply(500,null,["Retry-After:"+s]),this.remote_seqnum=t.cseq,!1}this.uas_pending_reply=!0,t.server_transaction.on("stateChanged",function t(){this.state!==e.Transactions.C.STATUS_ACCEPTED&&this.state!==e.Transactions.C.STATUS_COMPLETED&&this.state!==e.Transactions.C.STATUS_TERMINATED||(this.removeListener("stateChanged",t),i.uas_pending_reply=!1)})}t.hasHeader("contact")&&t.server_transaction.on("stateChanged",function(){this.state===e.Transactions.C.STATUS_ACCEPTED&&(i.remote_target=t.parseHeader("contact").uri)});break;case e.C.NOTIFY:t.hasHeader("contact")&&t.server_transaction.on("stateChanged",function(){this.state===e.Transactions.C.STATUS_COMPLETED&&(i.remote_target=t.parseHeader("contact").uri)})}return t.cseq>this.remote_seqnum&&(this.remote_seqnum=t.cseq),!0},sendRequest:function(e,t,i){var r=((i=i||{}).extraHeaders||[]).slice(),n=null;i.body&&(i.body.body?n=i.body:((n={}).body=i.body,i.contentType&&(n.contentType=i.contentType)));var o=this.createRequest(t,r,n);return new s(this,e,o).send(),o},receiveRequest:function(e){this.checkInDialogRequest(e)&&this.owner.receiveRequest(e)}},t.C=r,e.Dialog=t}},function(e,t,i){"use strict";e.exports=function(e){var t;return t=function(e,t,i){this.dialog=e,this.applicant=t,this.request=i,this.reattempt=!1,this.reattemptTimer=null},t.prototype={send:function(){var t=this,i=new e.RequestSender(this,this.dialog.owner.ua);i.send(),this.request.method===e.C.INVITE&&i.clientTransaction.state!==e.Transactions.C.STATUS_TERMINATED&&(this.dialog.uac_pending_reply=!0,i.clientTransaction.on("stateChanged",function i(){this.state!==e.Transactions.C.STATUS_ACCEPTED&&this.state!==e.Transactions.C.STATUS_COMPLETED&&this.state!==e.Transactions.C.STATUS_TERMINATED||(this.removeListener("stateChanged",i),t.dialog.uac_pending_reply=!1)}))},onRequestTimeout:function(){this.applicant.onRequestTimeout()},onTransportError:function(){this.applicant.onTransportError()},receiveResponse:function(t){var i=this;408===t.status_code||481===t.status_code?this.applicant.onDialogError(t):t.method===e.C.INVITE&&491===t.status_code?this.reattempt?this.applicant.receiveResponse(t):(this.request.cseq.value=this.dialog.local_seqnum+=1,this.reattemptTimer=e.Timers.setTimeout(function(){i.applicant.owner.status!==e.Session.C.STATUS_TERMINATED&&(i.reattempt=!0,i.request_sender.send())},this.getReattemptTimeout())):this.applicant.receiveResponse(t)}},t}},function(e,t,i){"use strict";e.exports=function(e){var t;(t=function(t,i){this.logger=i.getLogger("sip.requestsender"),this.ua=i,this.applicant=t,this.method=t.request.method,this.request=t.request,this.credentials=null,this.challenged=!1,this.staled=!1,i.status!==e.UA.C.STATUS_USER_CLOSED||this.method===e.C.BYE&&this.method===e.C.ACK||this.onTransportError()}).prototype={send:function(){switch(this.method){case"INVITE":this.clientTransaction=new e.Transactions.InviteClientTransaction(this,this.request,this.ua.transport);break;case"ACK":this.clientTransaction=new e.Transactions.AckClientTransaction(this,this.request,this.ua.transport);break;default:this.clientTransaction=new e.Transactions.NonInviteClientTransaction(this,this.request,this.ua.transport)}return this.clientTransaction.send(),this.clientTransaction},onRequestTimeout:function(){this.applicant.onRequestTimeout()},onTransportError:function(){this.applicant.onTransportError()},receiveResponse:function(t){var i,s,r,n=t.status_code;if(401===n||407===n){if(401===t.status_code?(s=t.parseHeader("www-authenticate"),r="authorization"):(s=t.parseHeader("proxy-authenticate"),r="proxy-authorization"),!s)return this.logger.warn(t.status_code+" with wrong or missing challenge, cannot authenticate"),void this.applicant.receiveResponse(t);if(!this.challenged||!this.staled&&!0===s.stale){if(this.credentials||(this.credentials=this.ua.configuration.authenticationFactory(this.ua)),!this.credentials.authenticate(this.request,s))return void this.applicant.receiveResponse(t);this.challenged=!0,s.stale&&(this.staled=!0),t.method===e.C.REGISTER?i=this.applicant.cseq+=1:this.request.dialog?i=this.request.dialog.local_seqnum+=1:(i=this.request.cseq+1,this.request.cseq=i),this.request.setHeader("cseq",i+" "+this.method),this.request.setHeader(r,this.credentials.toString()),this.send()}else this.applicant.receiveResponse(t)}else this.applicant.receiveResponse(t)}},e.RequestSender=t}},function(e,t,i){"use strict";e.exports=function(e){var t;(t=function(t){var i={};this.registrar=t.configuration.registrarServer,this.expires=t.configuration.registerExpires,this.contact=t.contact.toString(),this.contact+=";reg-id=1",this.contact+=';+sip.instance=""',this.call_id=e.Utils.createRandomToken(22),this.cseq=Math.floor(1e4*Math.random()),this.to_uri=t.configuration.uri,i.to_uri=this.to_uri,i.to_displayName=t.configuration.displayName,i.call_id=this.call_id,i.cseq=this.cseq,e.Utils.augment(this,e.ClientContext,[t,"REGISTER",this.registrar,{params:i}]),this.registrationTimer=null,this.registrationExpiredTimer=null,this.registered=!1,this.logger=t.getLogger("sip.registercontext")}).prototype={register:function(t){var i,s=this;this.options=t||{},(i=(this.options.extraHeaders||[]).slice()).push("Contact: "+this.contact+";expires="+this.expires),i.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.closeHeaders=this.options.closeWithHeaders?(this.options.extraHeaders||[]).slice():[],this.receiveResponse=function(t){var i,r,n,o=t.getHeaders("contact").length;if(t.cseq===this.cseq)switch(null!==this.registrationTimer&&(e.Timers.clearTimeout(this.registrationTimer),this.registrationTimer=null),!0){case/^1[0-9]{2}$/.test(t.status_code):this.emit("progress",t);break;case/^2[0-9]{2}$/.test(t.status_code):if(this.emit("accepted",t),t.hasHeader("expires")&&(r=t.getHeader("expires")),null!==this.registrationExpiredTimer&&(e.Timers.clearTimeout(this.registrationExpiredTimer),this.registrationExpiredTimer=null),!o){this.logger.warn("no Contact header in response to REGISTER, response ignored");break}for(;o--;){if((i=t.parseHeader("contact",o)).uri.user===this.ua.contact.uri.user){r=i.getParam("expires");break}i=null}if(!i){this.logger.warn("no Contact header pointing to us, response ignored");break}r||(r=this.expires),this.registrationTimer=e.Timers.setTimeout(function(){s.registrationTimer=null,s.register(s.options)},1e3*r-3e3),this.registrationExpiredTimer=e.Timers.setTimeout(function(){s.logger.warn("registration expired"),s.registered&&s.unregistered(null,e.C.causes.EXPIRES)},1e3*r),i.hasParam("temp-gruu")&&(this.ua.contact.temp_gruu=e.URI.parse(i.getParam("temp-gruu").replace(/"/g,""))),i.hasParam("pub-gruu")&&(this.ua.contact.pub_gruu=e.URI.parse(i.getParam("pub-gruu").replace(/"/g,""))),this.registered=!0,this.emit("registered",t||null);break;case/^423$/.test(t.status_code):t.hasHeader("min-expires")?(this.expires=t.getHeader("min-expires"),this.register(this.options)):(this.logger.warn("423 response received for REGISTER without Min-Expires"),this.registrationFailure(t,e.C.causes.SIP_FAILURE_CODE));break;default:n=e.Utils.sipErrorCause(t.status_code),this.registrationFailure(t,n)}},this.onRequestTimeout=function(){this.registrationFailure(null,e.C.causes.REQUEST_TIMEOUT)},this.onTransportError=function(){this.registrationFailure(null,e.C.causes.CONNECTION_ERROR)},this.cseq++,this.request.cseq=this.cseq,this.request.setHeader("cseq",this.cseq+" REGISTER"),this.request.extraHeaders=i,this.send()},registrationFailure:function(e,t){this.emit("failed",e||null,t||null)},onTransportClosed:function(){this.registered_before=this.registered,null!==this.registrationTimer&&(e.Timers.clearTimeout(this.registrationTimer),this.registrationTimer=null),null!==this.registrationExpiredTimer&&(e.Timers.clearTimeout(this.registrationExpiredTimer),this.registrationExpiredTimer=null),this.registered&&this.unregistered(null,e.C.causes.CONNECTION_ERROR)},onTransportConnected:function(){this.register(this.options)},close:function(){var e={all:!1,extraHeaders:this.closeHeaders};this.registered_before=this.registered,this.registered&&this.unregister(e)},unregister:function(t){var i;t=t||{},this.registered||t.all||this.logger.warn("Already unregistered, but sending an unregister anyways."),i=(t.extraHeaders||[]).slice(),this.registered=!1,null!==this.registrationTimer&&(e.Timers.clearTimeout(this.registrationTimer),this.registrationTimer=null),t.all?(i.push("Contact: *"),i.push("Expires: 0")):i.push("Contact: "+this.contact+";expires=0"),this.receiveResponse=function(t){var i;switch(!0){case/^1[0-9]{2}$/.test(t.status_code):this.emit("progress",t);break;case/^2[0-9]{2}$/.test(t.status_code):this.emit("accepted",t),null!==this.registrationExpiredTimer&&(e.Timers.clearTimeout(this.registrationExpiredTimer),this.registrationExpiredTimer=null),this.unregistered(t);break;default:i=e.Utils.sipErrorCause(t.status_code),this.unregistered(t,i)}},this.onRequestTimeout=function(){},this.onTransportError=function(){},this.cseq++,this.request.cseq=this.cseq,this.request.setHeader("cseq",this.cseq+" REGISTER"),this.request.extraHeaders=i,this.send()},unregistered:function(e,t){this.registered=!1,this.emit("unregistered",e||null,t||null)}},e.RegisterContext=t}},function(e,t,i){"use strict";e.exports=function(e){var t=function(e,t){};return t.prototype=Object.create(e.prototype,{close:{value:function(){}},getDescription:{value:function(e,t){}},hasDescription:{value:function(e){}},holdModifier:{value:function(e){}},setDescription:{value:function(e,t,i){}}}),t}},function(e,t,i){"use strict";e.exports=function(e){var t;((t=function(t,i,s,r){var n=s;if(void 0===s)throw new TypeError("Not enough arguments");if(this.ua=t,this.logger=t.getLogger("sip.clientcontext"),this.method=i,!(s=t.normalizeTarget(s)))throw new TypeError("Invalid target: "+n);(r=Object.create(r||Object.prototype)).extraHeaders=(r.extraHeaders||[]).slice(),this.request=new e.OutgoingRequest(this.method,s,this.ua,r.params,r.extraHeaders),r.body&&(this.body={},this.body.body=r.body,r.contentType&&(this.body.contentType=r.contentType),this.request.body=this.body),this.localIdentity=this.request.from,this.remoteIdentity=this.request.to,this.data={}}).prototype=Object.create(e.EventEmitter.prototype)).send=function(){return new e.RequestSender(this,this.ua).send(),this},t.prototype.cancel=function(t){(t=t||{}).extraHeaders=(t.extraHeaders||[]).slice();var i=e.Utils.getCancelReason(t.status_code,t.reason_phrase);this.request.cancel(i,t.extraHeaders),this.emit("cancel")},t.prototype.receiveResponse=function(t){var i=e.Utils.getReasonPhrase(t.status_code);switch(!0){case/^1[0-9]{2}$/.test(t.status_code):this.emit("progress",t,i);break;case/^2[0-9]{2}$/.test(t.status_code):this.ua.applicants[this]&&delete this.ua.applicants[this],this.emit("accepted",t,i);break;default:this.ua.applicants[this]&&delete this.ua.applicants[this],this.emit("rejected",t,i),this.emit("failed",t,i)}},t.prototype.onRequestTimeout=function(){this.emit("failed",null,e.C.causes.REQUEST_TIMEOUT)},t.prototype.onTransportError=function(){this.emit("failed",null,e.C.causes.CONNECTION_ERROR)},e.ClientContext=t}},function(e,t,i){"use strict";e.exports=function(e){var t;((t=function(t,i){this.ua=t,this.logger=t.getLogger("sip.servercontext"),this.request=i,i.method===e.C.INVITE?this.transaction=new e.Transactions.InviteServerTransaction(i,t):this.transaction=new e.Transactions.NonInviteServerTransaction(i,t),i.body&&(this.body=i.body),i.hasHeader("Content-Type")&&(this.contentType=i.getHeader("Content-Type")),this.method=i.method,this.data={},this.localIdentity=i.to,this.remoteIdentity=i.from}).prototype=Object.create(e.EventEmitter.prototype)).progress=function(e){return(e=Object.create(e||Object.prototype)).statusCode||(e.statusCode=180),e.minCode=100,e.maxCode=199,e.events=["progress"],this.reply(e)},t.prototype.accept=function(e){return(e=Object.create(e||Object.prototype)).statusCode||(e.statusCode=200),e.minCode=200,e.maxCode=299,e.events=["accepted"],this.reply(e)},t.prototype.reject=function(e){return(e=Object.create(e||Object.prototype)).statusCode||(e.statusCode=480),e.minCode=300,e.maxCode=699,e.events=["rejected","failed"],this.reply(e)},t.prototype.reply=function(t){var i,s=(t=t||{}).statusCode||100,r=t.minCode||100,n=t.maxCode||699,o=e.Utils.getReasonPhrase(s,t.reasonPhrase),a=t.extraHeaders||[],c=t.body,h=t.events||[];if(sn)throw new TypeError("Invalid statusCode: "+s);return i=this.request.reply(s,o,a,c),h.forEach(function(e){this.emit(e,i,o)},this),this},t.prototype.onRequestTimeout=function(){this.emit("failed",null,e.C.causes.REQUEST_TIMEOUT)},t.prototype.onTransportError=function(){this.emit("failed",null,e.C.causes.CONNECTION_ERROR)},e.ServerContext=t}},function(e,t,i){"use strict";e.exports=function(e){var t,s,r,n,o,a=i(24)(e),c={STATUS_NULL:0,STATUS_INVITE_SENT:1,STATUS_1XX_RECEIVED:2,STATUS_INVITE_RECEIVED:3,STATUS_WAITING_FOR_ANSWER:4,STATUS_ANSWERED:5,STATUS_WAITING_FOR_PRACK:6,STATUS_WAITING_FOR_ACK:7,STATUS_CANCELED:8,STATUS_TERMINATED:9,STATUS_ANSWERED_WAITING_FOR_PRACK:10,STATUS_EARLY_MEDIA:11,STATUS_CONFIRMED:12};(t=function(t){if(this.status=c.STATUS_NULL,this.dialog=null,this.pendingReinvite=!1,this.earlyDialogs={},!t)throw new e.Exceptions.SessionDescriptionHandlerMissing("A session description handler is required for the session to function");this.sessionDescriptionHandlerFactory=t,this.hasOffer=!1,this.hasAnswer=!1,this.timers={ackTimer:null,expiresTimer:null,invite2xxTimer:null,userNoAnswerTimer:null,rel1xxTimer:null,prackTimer:null},this.startTime=null,this.endTime=null,this.tones=null,this.local_hold=!1,this.disableRenegotiation=!1,this.early_sdp=null,this.rel100=e.C.supported.UNSUPPORTED}).prototype={dtmf:function(t,i){var s=[],r=this;if(i=i||{},void 0===t)throw new TypeError("Not enough arguments");if(this.status!==c.STATUS_CONFIRMED&&this.status!==c.STATUS_WAITING_FOR_ACK)throw new e.Exceptions.InvalidStateError(this.status);if("string"!=typeof t&&"number"!=typeof t||!t.toString().match(/^[0-9A-D#*,]+$/i))throw new TypeError("Invalid tones: "+t);for(t=t.toString().split("");t.length>0;)s.push(new a(this,t.shift(),i));if(this.tones)return this.tones=this.tones.concat(s),this;return this.tones=s,function t(){var s,n;if(r.status===c.STATUS_TERMINATED||!r.tones||0===r.tones.length)return r.tones=null,this;(s=r.tones.shift()).on("failed",function(){r.tones=null}),s.send(i),n=s.duration+s.interToneGap,e.Timers.setTimeout(t,n)}(),this},bye:function(t){var i=(t=Object.create(t||Object.prototype)).statusCode;if(this.status===c.STATUS_TERMINATED)return this.logger.error("Error: Attempted to send BYE in a terminated session."),this;if(this.logger.log("terminating Session"),i&&(i<200||i>=700))throw new TypeError("Invalid statusCode: "+i);return t.receiveResponse=function(){},this.sendRequest(e.C.BYE,t).terminated()},refer:function(t,i){if(i=i||{},this.status!==c.STATUS_CONFIRMED)throw new e.Exceptions.InvalidStateError(this.status);this.referContext=new e.ReferClientContext(this.ua,this,t,i),this.emit("referRequested",this.referContext),this.referContext.refer()},sendRequest:function(t,i){i=i||{};var s=this,r=new e.OutgoingRequest(t,this.dialog.remote_target,this.ua,{cseq:i.cseq||(this.dialog.local_seqnum+=1),call_id:this.dialog.id.call_id,from_uri:this.dialog.local_uri,from_tag:this.dialog.id.local_tag,to_uri:this.dialog.remote_uri,to_tag:this.dialog.id.remote_tag,route_set:this.dialog.route_set,statusCode:i.statusCode,reasonPhrase:i.reasonPhrase},i.extraHeaders||[],i.body);return new e.RequestSender({request:r,onRequestTimeout:function(){s.onRequestTimeout()},onTransportError:function(){s.onTransportError()},receiveResponse:i.receiveResponse||function(e){s.receiveNonInviteResponse(e)}},this.ua).send(),this.emit(t.toLowerCase(),r),this},close:function(){var t;if(this.status===c.STATUS_TERMINATED)return this;this.logger.log("closing INVITE session "+this.id),this.sessionDescriptionHandler&&this.sessionDescriptionHandler.close();for(t in this.timers)e.Timers.clearTimeout(this.timers[t]);this.dialog&&(this.dialog.terminate(),delete this.dialog);for(t in this.earlyDialogs)this.earlyDialogs[t].terminate(),delete this.earlyDialogs[t];return this.status=c.STATUS_TERMINATED,delete this.ua.sessions[this.id],this},createDialog:function(t,i,s){var r,n,o=t["UAS"===i?"to_tag":"from_tag"],a=t["UAS"===i?"from_tag":"to_tag"],c=t.call_id+o+a;if(n=this.earlyDialogs[c],s)return!!n||((n=new e.Dialog(this,t,i,e.Dialog.C.STATUS_EARLY)).error?(this.logger.error(n.error),this.failed(t,e.C.causes.INTERNAL_ERROR),!1):(this.earlyDialogs[c]=n,!0));if(n){n.update(t,i),this.dialog=n,delete this.earlyDialogs[c];for(var h in this.earlyDialogs)this.earlyDialogs[h].terminate(),delete this.earlyDialogs[h];return!0}return(r=new e.Dialog(this,t,i)).error?(this.logger.error(r.error),this.failed(t,e.C.causes.INTERNAL_ERROR),!1):(this.to_tag=t.to_tag,this.dialog=r,!0)},hold:function(t,i){if(this.status!==c.STATUS_WAITING_FOR_ACK&&this.status!==c.STATUS_CONFIRMED)throw new e.Exceptions.InvalidStateError(this.status);this.local_hold?this.logger.log("Session is already on hold, cannot put it on hold again"):((t=t||{}).modifiers=i||[],t.modifiers.push(this.sessionDescriptionHandler.holdModifier),this.local_hold=!0,this.sendReinvite(t))},unhold:function(t,i){if(this.status!==c.STATUS_WAITING_FOR_ACK&&this.status!==c.STATUS_CONFIRMED)throw new e.Exceptions.InvalidStateError(this.status);this.local_hold?(t=t||{},i&&(t.modifiers=i),this.local_hold=!1,this.sendReinvite(t)):this.logger.log("Session is not on hold, cannot unhold it")},reinvite:function(e,t){return e=e||{},t&&(e.modifiers=t),this.sendReinvite(e)},receiveReinvite:function(t){var i,s=this;if(s.emit("reinvite",this),"0"!==t.getHeader("Content-Length")||t.getHeader("Content-Type")){if(!this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type")))return t.reply(415),void this.emit("reinviteFailed",s);i=this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler,this.sessionDescriptionHandlerOptions,this.modifiers))}else i=this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions,this.modifiers);var r=this.receiveRequest;this.receiveRequest=function(t){t.method===e.C.ACK&&this.status===c.STATUS_WAITING_FOR_ACK&&this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type"))?(this.hasAnswer=!0,this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(function(){e.Timers.clearTimeout(this.timers.ackTimer),e.Timers.clearTimeout(this.timers.invite2xxTimer),this.status=c.STATUS_CONFIRMED,this.emit("confirmed",t)}.bind(this))):r.call(this,t)}.bind(this),i.catch(function(i){var r;i instanceof e.Exceptions.GetDescriptionError?r=500:i instanceof e.Exceptions.RenegotiationError?(s.emit("renegotiationError",i),s.logger.warn(i),r=488):(s.logger.error(i),r=488),t.reply(r),s.emit("reinviteFailed",s)}).then(function(e){var i=["Contact: "+s.contact];t.reply(200,null,i,e,function(){s.status=c.STATUS_WAITING_FOR_ACK,s.setACKTimer(),s.emit("reinviteAccepted",s)})})},sendReinvite:function(t){if(this.pendingReinvite)this.logger.warn("Reinvite in progress. Please wait until complete, then try again.");else{this.pendingReinvite=!0,(t=t||{}).modifiers=t.modifiers||[];var i=this,s=(t.extraHeaders||[]).slice();s.push("Contact: "+this.contact),s.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.sessionDescriptionHandler.getDescription(t.sessionDescriptionHandlerOptions,t.modifiers).then(function(t){i.sendRequest(e.C.INVITE,{extraHeaders:s,body:t,receiveResponse:i.receiveReinviteResponse.bind(i)})}).catch(function(t){if(t instanceof e.Exceptions.RenegotiationError)return i.pendingReinvite=!1,i.emit("renegotiationError",t),i.logger.warn("Renegotiation Error"),void i.logger.warn(t);i.logger.error("sessionDescriptionHandler error"),i.logger.error(t)})}},receiveRequest:function(t){switch(t.method){case e.C.BYE:t.reply(200),this.status===c.STATUS_CONFIRMED&&(this.emit("bye",t),this.terminated(t,e.C.causes.BYE));break;case e.C.INVITE:this.status===c.STATUS_CONFIRMED&&(this.logger.log("re-INVITE received"),this.receiveReinvite(t));break;case e.C.INFO:if(this.status===c.STATUS_CONFIRMED||this.status===c.STATUS_WAITING_FOR_ACK){if(this.onInfo)return this.onInfo(t);var i,s,r,n=t.getHeader("content-type"),o=/^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/,h=/^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;n&&(n.match(/^application\/dtmf-relay/i)?(t.body&&2===(i=t.body.split("\r\n",2)).length&&(o.test(i[0])&&(s=i[0].replace(o,"$2")),h.test(i[1])&&(r=parseInt(i[1].replace(h,"$2"),10))),new a(this,s,{duration:r}).init_incoming(t)):t.reply(415,null,["Accept: application/dtmf-relay"]))}break;case e.C.REFER:if(this.status===c.STATUS_CONFIRMED){this.logger.log("REFER received"),this.referContext=new e.ReferServerContext(this.ua,t);if(this.listeners("referRequested").length)this.emit("referRequested",this.referContext);else{this.logger.log("No referRequested listeners, automatically accepting and following the refer");var u={followRefer:!0};this.passedOptions&&(u.inviteOptions=this.passedOptions),this.referContext.accept(u,this.modifiers)}}break;case e.C.NOTIFY:if(this.referContext&&this.referContext instanceof e.ReferClientContext&&t.hasHeader("event")&&"refer"===t.getHeader("event"))return void this.referContext.receiveNotify(t);t.reply(200,"OK"),this.emit("notify",t)}},receiveReinviteResponse:function(t){var i=this;if(this.status!==c.STATUS_TERMINATED)switch(!0){case/^1[0-9]{2}$/.test(t.status_code):break;case/^2[0-9]{2}$/.test(t.status_code):if(this.status=c.STATUS_CONFIRMED,this.emit("ack",t.transaction.sendACK()),this.pendingReinvite=!1,e.Timers.clearTimeout(i.timers.invite2xxTimer),!this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type"))){this.logger.error("2XX response received to re-invite but did not have a description"),this.emit("renegotiationError",new e.Exceptions.RenegotiationError("2XX response received to re-invite but did not have a description"));break}this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).catch(function(t){i.logger.error("Could not set the description in 2XX response"),i.logger.error(t),i.emit("renegotiationError",t),i.sendRequest(e.C.BYE,{extraHeaders:[e.Utils.getReasonHeaderValue(488,"Not Acceptable Here")]})});break;default:this.disableRenegotiation=!0,this.pendingReinvite=!1,this.logger.log("Received a non 1XX or 2XX response to a re-invite"),this.emit("renegotiationError",new e.Exceptions.RenegotiationError("Invalid response to a re-invite"))}},acceptAndTerminate:function(t,i,s){var r=[];return i&&r.push("Reason: "+e.Utils.getReasonHeaderValue(i,s)),(this.dialog||this.createDialog(t,"UAC"))&&(this.emit("ack",t.transaction.sendACK()),this.sendRequest(e.C.BYE,{extraHeaders:r})),this},setInvite2xxTimer:function(t,i){var s=this,r=e.Timers.T1;this.timers.invite2xxTimer=e.Timers.setTimeout(function n(){if(s.status===c.STATUS_WAITING_FOR_ACK){s.logger.log("no ACK received, attempting to retransmit OK");var o=["Contact: "+s.contact];t.reply(200,null,o,i),r=Math.min(2*r,e.Timers.T2),s.timers.invite2xxTimer=e.Timers.setTimeout(n,r)}},r)},setACKTimer:function(){var t=this;this.timers.ackTimer=e.Timers.setTimeout(function(){t.status===c.STATUS_WAITING_FOR_ACK&&(t.logger.log("no ACK received for an extended period of time, terminating the call"),e.Timers.clearTimeout(t.timers.invite2xxTimer),t.sendRequest(e.C.BYE),t.terminated(null,e.C.causes.NO_ACK))},e.Timers.TIMER_H)},onTransportError:function(){this.status!==c.STATUS_CONFIRMED&&this.status!==c.STATUS_TERMINATED&&this.failed(null,e.C.causes.CONNECTION_ERROR)},onRequestTimeout:function(){this.status===c.STATUS_CONFIRMED?this.terminated(null,e.C.causes.REQUEST_TIMEOUT):this.status!==c.STATUS_TERMINATED&&(this.failed(null,e.C.causes.REQUEST_TIMEOUT),this.terminated(null,e.C.causes.REQUEST_TIMEOUT))},onDialogError:function(t){this.status===c.STATUS_CONFIRMED?this.terminated(t,e.C.causes.DIALOG_ERROR):this.status!==c.STATUS_TERMINATED&&(this.failed(t,e.C.causes.DIALOG_ERROR),this.terminated(t,e.C.causes.DIALOG_ERROR))},failed:function(e,t){return this.status===c.STATUS_TERMINATED?this:(this.emit("failed",e||null,t||null),this)},rejected:function(e,t){return this.emit("rejected",e||null,t||null),this},canceled:function(){return this.emit("cancel"),this},accepted:function(t,i){return i=e.Utils.getReasonPhrase(t&&t.status_code,i),this.startTime=new Date,this.replacee&&(this.replacee.emit("replaced",this),this.replacee.terminate()),this.emit("accepted",t,i),this},terminated:function(e,t){return this.status===c.STATUS_TERMINATED?this:(this.endTime=new Date,this.close(),this.emit("terminated",e||null,t||null),this)},connecting:function(e){return this.emit("connecting",{request:e}),this}},t.C=c,e.Session=t,(s=function(t,i){function s(e,t){i.hasHeader(e)&&i.getHeader(e).toLowerCase().indexOf("100rel")>=0&&(n.rel100=t)}var r,n=this,o=i.getHeader("Content-Type"),a=i.parseHeader("Content-Disposition");if(e.Utils.augment(this,e.ServerContext,[t,i]),e.Utils.augment(this,e.Session,[t.configuration.sessionDescriptionHandlerFactory]),a&&"render"===a.type&&(this.renderbody=i.body,this.rendertype=o),this.status=c.STATUS_INVITE_RECEIVED,this.from_tag=i.from_tag,this.id=i.call_id+this.from_tag,this.request=i,this.contact=this.ua.contact.toString(),this.receiveNonInviteResponse=function(){},this.logger=t.getLogger("sip.inviteservercontext",this.id),this.ua.sessions[this.id]=this,i.hasHeader("expires")&&(r=1e3*i.getHeader("expires")),s("require",e.C.supported.REQUIRED),s("supported",e.C.supported.SUPPORTED),i.to_tag=e.Utils.newTag(),this.createDialog(i,"UAS",!0)){var h={extraHeaders:["Contact: "+n.contact]};n.rel100!==e.C.supported.REQUIRED&&n.progress(h),n.status=c.STATUS_WAITING_FOR_ANSWER,n.timers.userNoAnswerTimer=e.Timers.setTimeout(function(){i.reply(408),n.failed(i,e.C.causes.NO_ANSWER),n.terminated(i,e.C.causes.NO_ANSWER)},n.ua.configuration.noAnswerTimeout),r&&(n.timers.expiresTimer=e.Timers.setTimeout(function(){n.status===c.STATUS_WAITING_FOR_ANSWER&&(i.reply(487),n.failed(i,e.C.causes.EXPIRES),n.terminated(i,e.C.causes.EXPIRES))},r))}else i.reply(500,"Missing Contact header field")}).prototype={reject:function(t){if(this.status===c.STATUS_TERMINATED)throw new e.Exceptions.InvalidStateError(this.status);return this.logger.log("rejecting RTCSession"),e.ServerContext.prototype.reject.call(this,t),this.terminated()},terminate:function(t){var i,s=((t=t||{}).extraHeaders||[]).slice(),r=t.body,n=this;return this.status===c.STATUS_WAITING_FOR_ACK&&this.request.server_transaction.state!==e.Transactions.C.STATUS_TERMINATED?(i=this.dialog,this.receiveRequest=function(t){t.method===e.C.ACK&&(this.sendRequest(e.C.BYE,{extraHeaders:s,body:r}),i.terminate())},this.request.server_transaction.on("stateChanged",function(){this.state===e.Transactions.C.STATUS_TERMINATED&&this.dialog&&(this.request=new e.OutgoingRequest(e.C.BYE,this.dialog.remote_target,this.ua,{cseq:this.dialog.local_seqnum+=1,call_id:this.dialog.id.call_id,from_uri:this.dialog.local_uri,from_tag:this.dialog.id.local_tag,to_uri:this.dialog.remote_uri,to_tag:this.dialog.id.remote_tag,route_set:this.dialog.route_set},s,r),new e.RequestSender({request:this.request,onRequestTimeout:function(){n.onRequestTimeout()},onTransportError:function(){n.onTransportError()},receiveResponse:function(){}},this.ua).send(),i.terminate())}),this.emit("bye",this.request),this.terminated(),this.dialog=i,this.ua.dialogs[i.id.toString()]=i):this.status===c.STATUS_CONFIRMED?this.bye(t):this.reject(t),this},progress:function(t){function i(){r=t.statusCode||183,this.status=c.STATUS_WAITING_FOR_PRACK,o.push("Contact: "+this.contact),o.push("Require: 100rel"),o.push("RSeq: "+Math.floor(1e4*Math.random())),this.sessionDescriptionHandler.getDescription(t.sessionDescriptionHandlerOptions,t.modifiers).then(function(t){if(!this.isCanceled&&this.status!==c.STATUS_TERMINATED){this.early_sdp=t.body,this[this.hasOffer?"hasAnswer":"hasOffer"]=!0;var i=e.Timers.T1;this.timers.rel1xxTimer=e.Timers.setTimeout(function s(){this.request.reply(r,null,o,t),i*=2,this.timers.rel1xxTimer=e.Timers.setTimeout(s.bind(this),i)}.bind(this),i),this.timers.prackTimer=e.Timers.setTimeout(function(){this.status===c.STATUS_WAITING_FOR_PRACK&&(this.logger.log("no PRACK received, rejecting the call"),e.Timers.clearTimeout(this.timers.rel1xxTimer),this.request.reply(504),this.terminated(null,e.C.causes.NO_PRACK))}.bind(this),64*e.Timers.T1),s=this.request.reply(r,n,o,t),this.emit("progress",s,n)}}.bind(this),function(){this.request.reply(480),this.failed(null,e.C.causes.WEBRTC_ERROR),this.terminated(null,e.C.causes.WEBRTC_ERROR)}.bind(this))}var s,r=(t=t||{}).statusCode||180,n=t.reasonPhrase,o=(t.extraHeaders||[]).slice(),a=t.body;if(r<100||r>199)throw new TypeError("Invalid statusCode: "+r);return this.isCanceled||this.status===c.STATUS_TERMINATED?this:(100!==t.statusCode&&(this.rel100===e.C.supported.REQUIRED||this.rel100===e.C.supported.SUPPORTED&&t.rel100||this.rel100===e.C.supported.SUPPORTED&&this.ua.configuration.rel100===e.C.supported.REQUIRED)?(this.sessionDescriptionHandler=this.setupSessionDescriptionHandler(),this.sessionDescriptionHandler.hasDescription(this.request.getHeader("Content-Type"))?(this.hasOffer=!0,this.sessionDescriptionHandler.setDescription(this.request.body,t.sessionDescriptionHandlerOptions,t.modifiers).then(i.apply(this)).catch(function(t){this.logger.warn("invalid description"),this.logger.warn(t),this.failed(null,e.C.causes.WEBRTC_ERROR),this.terminated(null,e.C.causes.WEBRTC_ERROR)}.bind(this))):i.apply(this)):function(){s=this.request.reply(r,n,o,a),this.emit("progress",s,n)}.apply(this),this)},accept:function(t){t=t||{},this.onInfo=t.onInfo;var i=this,s=this.request,r=(t.extraHeaders||[]).slice(),n=function(t){var n;r.push("Contact: "+i.contact),r.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),i.hasOffer?i.hasAnswer=!0:i.hasOffer=!0,n=s.reply(200,null,r,t,function(){i.status=c.STATUS_WAITING_FOR_ACK,i.setInvite2xxTimer(s,t),i.setACKTimer()},function(){i.failed(null,e.C.causes.CONNECTION_ERROR),i.terminated(null,e.C.causes.CONNECTION_ERROR)}),i.status!==c.STATUS_TERMINATED&&i.accepted(n,e.Utils.getReasonPhrase(200))},o=function(){i.status!==c.STATUS_TERMINATED&&(i.request.reply(480),i.failed(null,e.C.causes.WEBRTC_ERROR),i.terminated(null,e.C.causes.WEBRTC_ERROR))};if(this.status===c.STATUS_WAITING_FOR_PRACK)return this.status=c.STATUS_ANSWERED_WAITING_FOR_PRACK,this;if(this.status===c.STATUS_WAITING_FOR_ANSWER)this.status=c.STATUS_ANSWERED;else if(this.status!==c.STATUS_EARLY_MEDIA)throw new e.Exceptions.InvalidStateError(this.status);if(!this.createDialog(s,"UAS"))return s.reply(500,"Missing Contact header field"),this;if(e.Timers.clearTimeout(this.timers.userNoAnswerTimer),this.status===c.STATUS_EARLY_MEDIA)n({});else if(this.sessionDescriptionHandler=this.setupSessionDescriptionHandler(),"0"!==this.request.getHeader("Content-Length")||this.request.getHeader("Content-Type")){if(!this.sessionDescriptionHandler.hasDescription(this.request.getHeader("Content-Type")))return void this.request.reply(415);this.hasOffer=!0,this.sessionDescriptionHandler.setDescription(this.request.body,t.sessionDescriptionHandlerOptions,t.modifiers).then(function(){return this.sessionDescriptionHandler.getDescription(t.sessionDescriptionHandlerOptions,t.modifiers)}.bind(this)).catch(o).then(n)}else this.sessionDescriptionHandler.getDescription(t.sessionDescriptionHandlerOptions,t.modifiers).catch(o).then(n);return this},receiveRequest:function(i){function s(){var t,s;e.Timers.clearTimeout(this.timers.ackTimer),e.Timers.clearTimeout(this.timers.invite2xxTimer),this.status=c.STATUS_CONFIRMED,t=i.getHeader("Content-Type"),(s=i.getHeader("Content-Disposition"))&&"render"===s.type&&(this.renderbody=i.body,this.rendertype=t),this.emit("confirmed",i)}switch(i.method){case e.C.CANCEL:this.status!==c.STATUS_WAITING_FOR_ANSWER&&this.status!==c.STATUS_WAITING_FOR_PRACK&&this.status!==c.STATUS_ANSWERED_WAITING_FOR_PRACK&&this.status!==c.STATUS_EARLY_MEDIA&&this.status!==c.STATUS_ANSWERED||(this.status=c.STATUS_CANCELED,this.request.reply(487),this.canceled(i),this.rejected(i,e.C.causes.CANCELED),this.failed(i,e.C.causes.CANCELED),this.terminated(i,e.C.causes.CANCELED));break;case e.C.ACK:this.status===c.STATUS_WAITING_FOR_ACK&&(this.sessionDescriptionHandler.hasDescription(i.getHeader("Content-Type"))?(this.hasAnswer=!0,this.sessionDescriptionHandler.setDescription(i.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(s.bind(this),function(t){this.logger.warn(t),this.terminate({statusCode:"488",reasonPhrase:"Bad Media Description"}),this.failed(i,e.C.causes.BAD_MEDIA_DESCRIPTION),this.terminated(i,e.C.causes.BAD_MEDIA_DESCRIPTION)}.bind(this))):s.apply(this));break;case e.C.PRACK:this.status===c.STATUS_WAITING_FOR_PRACK||this.status===c.STATUS_ANSWERED_WAITING_FOR_PRACK?this.hasAnswer?(e.Timers.clearTimeout(this.timers.rel1xxTimer),e.Timers.clearTimeout(this.timers.prackTimer),i.reply(200),this.status===c.STATUS_ANSWERED_WAITING_FOR_PRACK&&(this.status=c.STATUS_EARLY_MEDIA,this.accept()),this.status=c.STATUS_EARLY_MEDIA):(this.sessionDescriptionHandler=this.setupSessionDescriptionHandler(),this.sessionDescriptionHandler.hasDescription(i.getHeader("Content-Type"))?(this.hasAnswer=!0,this.sessionDescriptionHandler.setDescription(i.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(function(){e.Timers.clearTimeout(this.timers.rel1xxTimer),e.Timers.clearTimeout(this.timers.prackTimer),i.reply(200),this.status===c.STATUS_ANSWERED_WAITING_FOR_PRACK&&(this.status=c.STATUS_EARLY_MEDIA,this.accept()),this.status=c.STATUS_EARLY_MEDIA}.bind(this),function(t){this.logger.warn(t),this.terminate({statusCode:"488",reasonPhrase:"Bad Media Description"}),this.failed(i,e.C.causes.BAD_MEDIA_DESCRIPTION),this.terminated(i,e.C.causes.BAD_MEDIA_DESCRIPTION)}.bind(this))):(this.terminate({statusCode:"488",reasonPhrase:"Bad Media Description"}),this.failed(i,e.C.causes.BAD_MEDIA_DESCRIPTION),this.terminated(i,e.C.causes.BAD_MEDIA_DESCRIPTION))):this.status===c.STATUS_EARLY_MEDIA&&i.reply(200);break;default:t.prototype.receiveRequest.apply(this,[i])}},setupSessionDescriptionHandler:function(){return this.sessionDescriptionHandler?this.sessionDescriptionHandler:this.sessionDescriptionHandlerFactory(this,this.ua.configuration.sessionDescriptionHandlerFactoryOptions)},onTransportError:function(){this.status!==c.STATUS_CONFIRMED&&this.status!==c.STATUS_TERMINATED&&this.failed(null,e.C.causes.CONNECTION_ERROR)},onRequestTimeout:function(){this.status===c.STATUS_CONFIRMED?this.terminated(null,e.C.causes.REQUEST_TIMEOUT):this.status!==c.STATUS_TERMINATED&&(this.failed(null,e.C.causes.REQUEST_TIMEOUT),this.terminated(null,e.C.causes.REQUEST_TIMEOUT))}},e.InviteServerContext=s,(r=function(t,i,s,r){s=s||{},this.passedOptions=s,s.params=Object.create(s.params||Object.prototype);var n=(s.extraHeaders||[]).slice(),o=t.configuration.sessionDescriptionHandlerFactory;if(this.sessionDescriptionHandlerFactoryOptions=t.configuration.sessionDescriptionHandlerFactoryOptions||{},this.sessionDescriptionHandlerOptions=s.sessionDescriptionHandlerOptions||{},this.modifiers=r,this.inviteWithoutSdp=s.inviteWithoutSdp||!1,this.anonymous=s.anonymous||!1,this.renderbody=s.renderbody||null,this.rendertype=s.rendertype||"text/plain",this.from_tag=e.Utils.newTag(),s.params.from_tag=this.from_tag,this.contact=t.contact.toString({anonymous:this.anonymous,outbound:this.anonymous?!t.contact.temp_gruu:!t.contact.pub_gruu}),this.anonymous&&(s.params.from_displayName="Anonymous",s.params.from_uri="sip:anonymous@anonymous.invalid",n.push("P-Preferred-Identity: "+t.configuration.uri.toString()),n.push("Privacy: id")),n.push("Contact: "+this.contact),n.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.inviteWithoutSdp&&this.renderbody&&(n.push("Content-Type: "+this.rendertype),n.push("Content-Disposition: render;handling=optional")),t.configuration.rel100===e.C.supported.REQUIRED&&n.push("Require: 100rel"),t.configuration.replaces===e.C.supported.REQUIRED&&n.push("Require: replaces"),s.extraHeaders=n,e.Utils.augment(this,e.ClientContext,[t,e.C.INVITE,i,s]),e.Utils.augment(this,e.Session,[o]),this.status!==c.STATUS_NULL)throw new e.Exceptions.InvalidStateError(this.status);this.isCanceled=!1,this.received_100=!1,this.method=e.C.INVITE,this.receiveNonInviteResponse=this.receiveResponse,this.receiveResponse=this.receiveInviteResponse,this.logger=t.getLogger("sip.inviteclientcontext"),t.applicants[this]=this,this.id=this.request.call_id+this.from_tag,this.onInfo=s.onInfo}).prototype={invite:function(){var t=this;return this.ua.sessions[this.id]=this,this.inviteWithoutSdp?(this.request.body=t.renderbody,this.status=c.STATUS_INVITE_SENT,this.send()):(this.sessionDescriptionHandler=this.sessionDescriptionHandlerFactory(this,this.sessionDescriptionHandlerFactoryOptions),this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions,this.modifiers).then(function(e){t.isCanceled||t.status===c.STATUS_TERMINATED||(t.hasOffer=!0,t.request.body=e,t.status=c.STATUS_INVITE_SENT,t.send())},function(){t.status!==c.STATUS_TERMINATED&&(t.failed(null,e.C.causes.WEBRTC_ERROR),t.terminated(null,e.C.causes.WEBRTC_ERROR))})),this},receiveInviteResponse:function(t){var i,s=this,r=t.call_id+t.from_tag+t.to_tag,n=[],o={};if(this.status!==c.STATUS_TERMINATED&&t.method===e.C.INVITE){if(this.dialog&&t.status_code>=200&&t.status_code<=299){if(r!==this.dialog.id.toString()){if(!this.createDialog(t,"UAC",!0))return;return this.emit("ack",t.transaction.sendACK({body:e.Utils.generateFakeSDP(t.body)})),this.earlyDialogs[r].sendRequest(this,e.C.BYE),void(this.status!==c.STATUS_CONFIRMED&&(this.failed(t,e.C.causes.WEBRTC_ERROR),this.terminated(t,e.C.causes.WEBRTC_ERROR)))}if(this.status===c.STATUS_CONFIRMED)return void this.emit("ack",t.transaction.sendACK());if(!this.hasAnswer)return}if(this.dialog&&t.status_code<200){if(-1!==this.dialog.pracked.indexOf(t.getHeader("rseq"))||this.dialog.pracked[this.dialog.pracked.length-1]>=t.getHeader("rseq")&&this.dialog.pracked.length>0)return;if(!this.earlyDialogs[r]&&!this.createDialog(t,"UAC",!0))return;if(-1!==this.earlyDialogs[r].pracked.indexOf(t.getHeader("rseq"))||this.earlyDialogs[r].pracked[this.earlyDialogs[r].pracked.length-1]>=t.getHeader("rseq")&&this.earlyDialogs[r].pracked.length>0)return;return n.push("RAck: "+t.getHeader("rseq")+" "+t.getHeader("cseq")),this.earlyDialogs[r].pracked.push(t.getHeader("rseq")),void this.earlyDialogs[r].sendRequest(this,e.C.PRACK,{extraHeaders:n,body:e.Utils.generateFakeSDP(t.body)})}if(this.isCanceled)t.status_code>=100&&t.status_code<200?(this.request.cancel(this.cancelReason,n),this.canceled(null)):t.status_code>=200&&t.status_code<299?(this.acceptAndTerminate(t),this.emit("bye",this.request)):t.status_code>=300&&(i=e.C.REASON_PHRASE[t.status_code]||e.C.causes.CANCELED,this.rejected(t,i),this.failed(t,i),this.terminated(t,i));else switch(!0){case/^100$/.test(t.status_code):this.received_100=!0,this.emit("progress",t);break;case/^1[0-9]{2}$/.test(t.status_code):if(!t.to_tag){this.logger.warn("1xx response received without to tag");break}if(t.hasHeader("contact")&&!this.createDialog(t,"UAC",!0))break;if(this.status=c.STATUS_1XX_RECEIVED,t.hasHeader("require")&&-1!==t.getHeader("require").indexOf("100rel")){if(this.dialog||!this.earlyDialogs[r])break;if(-1!==this.earlyDialogs[r].pracked.indexOf(t.getHeader("rseq"))||this.earlyDialogs[r].pracked[this.earlyDialogs[r].pracked.length-1]>=t.getHeader("rseq")&&this.earlyDialogs[r].pracked.length>0)return;if(this.sessionDescriptionHandler=this.sessionDescriptionHandlerFactory(this,this.sessionDescriptionHandlerFactoryOptions),this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type")))if(this.hasOffer){if(!this.createDialog(t,"UAC"))break;this.hasAnswer=!0,this.dialog.pracked.push(t.getHeader("rseq")),this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(function(){n.push("RAck: "+t.getHeader("rseq")+" "+t.getHeader("cseq")),s.sendRequest(e.C.PRACK,{extraHeaders:n,receiveResponse:function(){}}),s.status=c.STATUS_EARLY_MEDIA,s.emit("progress",t)},function(i){s.logger.warn(i),s.acceptAndTerminate(t,488,"Not Acceptable Here"),s.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION)})}else{var a=this.earlyDialogs[r],h=a.sessionDescriptionHandler=this.sessionDescriptionHandlerFactory(this,this.sessionDescriptionHandlerOptions);a.pracked.push(t.getHeader("rseq")),h.setDescription(t.body,s.sessionDescriptionHandlerOptions,s.modifers).then(h.getDescription.bind(h,s.sessionDescriptionHandlerOptions,s.modifiers)).then(function(i){n.push("RAck: "+t.getHeader("rseq")+" "+t.getHeader("cseq")),a.sendRequest(s,e.C.PRACK,{extraHeaders:n,body:i}),s.status=c.STATUS_EARLY_MEDIA,s.emit("progress",t)}).catch(function(i){if(i instanceof e.Exceptions.GetDescriptionError){if(a.pracked.push(t.getHeader("rseq")),s.status===c.STATUS_TERMINATED)return;s.failed(null,e.C.causes.WEBRTC_ERROR),s.terminated(null,e.C.causes.WEBRTC_ERROR)}else a.pracked.splice(a.pracked.indexOf(t.getHeader("rseq")),1),s.logger.warn("invalid description"),s.logger.warn(i)})}else n.push("RAck: "+t.getHeader("rseq")+" "+t.getHeader("cseq")),this.earlyDialogs[r].pracked.push(t.getHeader("rseq")),this.earlyDialogs[r].sendRequest(this,e.C.PRACK,{extraHeaders:n}),this.emit("progress",t)}else this.emit("progress",t);break;case/^2[0-9]{2}$/.test(t.status_code):if(this.request.cseq+" "+this.request.method!==t.getHeader("cseq"))break;if(this.status===c.STATUS_EARLY_MEDIA&&this.dialog){this.status=c.STATUS_CONFIRMED,o={},this.renderbody&&(n.push("Content-Type: "+this.rendertype),o.extraHeaders=n,o.body=this.renderbody),this.emit("ack",t.transaction.sendACK(o)),this.accepted(t);break}if(this.dialog)break;if(this.hasOffer)if(this.hasAnswer)this.renderbody&&(n.push("Content-Type: "+s.rendertype),o.extraHeaders=n,o.body=this.renderbody),this.emit("ack",t.transaction.sendACK(o));else{if(!this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type"))){this.acceptAndTerminate(t,400,"Missing session description"),this.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION);break}if(!this.createDialog(t,"UAC"))break;this.hasAnswer=!0,this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(function(){var e={};s.status=c.STATUS_CONFIRMED,s.renderbody&&(n.push("Content-Type: "+s.rendertype),e.extraHeaders=n,e.body=s.renderbody),s.emit("ack",t.transaction.sendACK(e)),s.accepted(t)},function(i){s.logger.warn(i),s.acceptAndTerminate(t,488,"Not Acceptable Here"),s.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION)})}else if(this.earlyDialogs[r]&&this.earlyDialogs[r].sessionDescriptionHandler){if(this.hasOffer=!0,this.hasAnswer=!0,this.sessionDescriptionHandler=this.earlyDialogs[r].sessionDescriptionHandler,!this.createDialog(t,"UAC"))break;this.status=c.STATUS_CONFIRMED,this.emit("ack",t.transaction.sendACK()),this.accepted(t)}else{if(this.sessionDescriptionHandler=this.sessionDescriptionHandlerFactory(this,this.sessionDescriptionHandlerFactoryOptions),!this.sessionDescriptionHandler.hasDescription(t.getHeader("Content-Type"))){this.acceptAndTerminate(t,400,"Missing session description"),this.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION);break}if(!this.createDialog(t,"UAC"))break;this.hasOffer=!0,this.sessionDescriptionHandler.setDescription(t.body,this.sessionDescriptionHandlerOptions,this.modifiers).then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler,this.sessionDescriptionHandlerOptions,this.modifiers)).then(function(e){s.isCanceled||s.status===c.STATUS_TERMINATED||(s.status=c.STATUS_CONFIRMED,s.hasAnswer=!0,s.emit("ack",t.transaction.sendACK({body:e})),s.accepted(t))}).catch(function(i){i instanceof e.Exceptions.GetDescriptionError?s.logger.warn("there was a problem"):(s.logger.warn("invalid description"),s.logger.warn(i),s.acceptAndTerminate(t,488,"Invalid session description"),s.failed(t,e.C.causes.BAD_MEDIA_DESCRIPTION))})}break;default:i=e.Utils.sipErrorCause(t.status_code),this.rejected(t,i),this.failed(t,i),this.terminated(t,i)}}},cancel:function(t){if(t=t||{},t.extraHeaders=(t.extraHeaders||[]).slice(),this.status===c.STATUS_TERMINATED||this.status===c.STATUS_CONFIRMED)throw new e.Exceptions.InvalidStateError(this.status);this.logger.log("canceling RTCSession");var i=e.Utils.getCancelReason(t.status_code,t.reason_phrase);return this.status===c.STATUS_NULL||this.status===c.STATUS_INVITE_SENT&&!this.received_100?(this.isCanceled=!0,this.cancelReason=i):this.status!==c.STATUS_INVITE_SENT&&this.status!==c.STATUS_1XX_RECEIVED&&this.status!==c.STATUS_EARLY_MEDIA||this.request.cancel(i,t.extraHeaders),this.canceled()},terminate:function(e){return this.status===c.STATUS_TERMINATED?this:(this.status===c.STATUS_WAITING_FOR_ACK||this.status===c.STATUS_CONFIRMED?this.bye(e):this.cancel(e),this)},receiveRequest:function(i){return i.method,e.C.CANCEL,i.method===e.C.ACK&&this.status===c.STATUS_WAITING_FOR_ACK&&(e.Timers.clearTimeout(this.timers.ackTimer),e.Timers.clearTimeout(this.timers.invite2xxTimer),this.status=c.STATUS_CONFIRMED,this.accepted()),t.prototype.receiveRequest.apply(this,[i])},onTransportError:function(){this.status!==c.STATUS_CONFIRMED&&this.status!==c.STATUS_TERMINATED&&this.failed(null,e.C.causes.CONNECTION_ERROR)},onRequestTimeout:function(){this.status===c.STATUS_CONFIRMED?this.terminated(null,e.C.causes.REQUEST_TIMEOUT):this.status!==c.STATUS_TERMINATED&&(this.failed(null,e.C.causes.REQUEST_TIMEOUT),this.terminated(null,e.C.causes.REQUEST_TIMEOUT))}},e.InviteClientContext=r,(o=function(t,i,s,r){if(this.options=r||{},this.extraHeaders=(this.options.extraHeaders||[]).slice(),void 0===t||void 0===i||void 0===s)throw new TypeError("Not enough arguments");e.Utils.augment(this,e.ClientContext,[t,e.C.REFER,i.remoteIdentity.uri.toString(),r]),this.applicant=i;if(s instanceof e.InviteServerContext||s instanceof e.InviteClientContext)this.target='"'+s.remoteIdentity.friendlyName+'" <'+s.dialog.remote_target.toString()+"?Replaces="+s.dialog.id.call_id+"%3Bto-tag%3D"+s.dialog.id.remote_tag+"%3Bfrom-tag%3D"+s.dialog.id.local_tag+">";else{try{this.target=e.Grammar.parse(s,"Refer_To").uri||s}catch(e){this.logger.debug(".refer() cannot parse Refer_To from",s),this.logger.debug("...falling through to normalizeTarget()")}if(this.target=this.ua.normalizeTarget(this.target),!this.target)throw new TypeError("Invalid target: "+s)}this.ua&&this.extraHeaders.push("Referred-By: <"+this.ua.configuration.uri+">"),this.extraHeaders.push("Contact: "+i.contact),this.extraHeaders.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.extraHeaders.push("Refer-To: "+this.target)}).prototype={refer:function(t){t=t||{};var i=(this.extraHeaders||[]).slice();return t.extraHeaders&&i.concat(t.extraHeaders),this.applicant.sendRequest(e.C.REFER,{extraHeaders:this.extraHeaders,receiveResponse:function(e){/^1[0-9]{2}$/.test(e.status_code)?this.emit("referRequestProgress",this):/^2[0-9]{2}$/.test(e.status_code)?this.emit("referRequestAccepted",this):/^[4-6][0-9]{2}$/.test(e.status_code)&&this.emit("referRequestRejected",this),t.receiveResponse&&t.receiveResponse(e)}.bind(this)}),this},receiveNotify:function(t){if(t.hasHeader("Content-Type")&&-1!==t.getHeader("Content-Type").search(/^message\/sipfrag/)){var i=e.Grammar.parse(t.body,"sipfrag");if(-1===i)return void t.reply(489,"Bad Event");switch(!0){case/^1[0-9]{2}$/.test(i.status_code):this.emit("referProgress",this);break;case/^2[0-9]{2}$/.test(i.status_code):this.emit("referAccepted",this),!this.options.activeAfterTransfer&&this.applicant.terminate&&this.applicant.terminate();break;default:this.emit("referRejected",this)}return t.reply(200),void this.emit("notify",t)}t.reply(489,"Bad Event")}},e.ReferClientContext=o,(n=function(t,i){if(e.Utils.augment(this,e.ServerContext,[t,i]),this.ua=t,this.status=c.STATUS_INVITE_RECEIVED,this.from_tag=i.from_tag,this.id=i.call_id+this.from_tag,this.request=i,this.contact=this.ua.contact.toString(),this.logger=t.getLogger("sip.referservercontext",this.id),!this.request.hasHeader("refer-to"))return this.logger.warn("Invalid REFER packet. A refer-to header is required. Rejecting refer."),void this.reject();this.referTo=this.request.parseHeader("refer-to"),this.referredSession=this.ua.findSession(i),this.cseq=Math.floor(1e4*Math.random()),this.call_id=this.request.call_id,this.from_uri=this.request.to.uri,this.from_tag=this.request.to.parameters.tag,this.remote_target=this.request.headers.Contact[0].parsed.uri,this.to_uri=this.request.from.uri,this.to_tag=this.request.from_tag,this.route_set=this.request.getHeaders("record-route"),this.receiveNonInviteResponse=function(){},this.request.hasHeader("referred-by")&&(this.referredBy=this.request.getHeader("referred-by")),this.referTo.uri.hasHeader("replaces")&&(this.replaces=this.referTo.uri.getHeader("replaces")),this.status=c.STATUS_WAITING_FOR_ANSWER}).prototype={progress:function(){if(this.status!==c.STATUS_WAITING_FOR_ANSWER)throw new e.Exceptions.InvalidStateError(this.status);this.request.reply(100)},reject:function(t){if(this.status===c.STATUS_TERMINATED)throw new e.Exceptions.InvalidStateError(this.status);this.logger.log("Rejecting refer"),this.status=c.STATUS_TERMINATED,e.ServerContext.prototype.reject.call(this,t),this.emit("referRequestRejected",this)},accept:function(t,i){if(t=t||{},this.status!==c.STATUS_WAITING_FOR_ANSWER)throw new e.Exceptions.InvalidStateError(this.status);if(this.status=c.STATUS_ANSWERED,this.request.reply(202,"Accepted"),this.emit("referRequestAccepted",this),t.followRefer){this.logger.log("Accepted refer, attempting to automatically follow it");var s=this.referTo.uri;if(!s.scheme.match("^sips?$"))return this.logger.error("SIP.js can only automatically follow SIP refer target"),void this.reject();var r=t.inviteOptions||{},n=(r.extraHeaders||[]).slice();this.replaces&&n.push("Replaces: "+decodeURIComponent(this.replaces)),this.referredBy&&n.push("Referred-By: "+this.referredBy),r.extraHeaders=n,s.clearHeaders(),this.targetSession=this.ua.invite(s,r,i),this.emit("referInviteSent",this),this.targetSession.once("progress",function(){this.sendNotify("SIP/2.0 100 Trying"),this.emit("referProgress",this),this.referredSession&&this.referredSession.emit("referProgress",this)}.bind(this)),this.targetSession.once("accepted",function(){this.logger.log("Successfully followed the refer"),this.sendNotify("SIP/2.0 200 OK"),this.emit("referAccepted",this),this.referredSession&&this.referredSession.emit("referAccepted",this)}.bind(this));var o=function(e){if(this.status!==c.STATUS_TERMINATED){if(this.logger.log("Refer was not successful. Resuming session"),e&&429===e.status_code)return this.logger.log("Alerting referrer that identity is required."),void this.sendNotify("SIP/2.0 429 Provide Referrer Identity");this.sendNotify("SIP/2.0 603 Declined"),this.status=c.STATUS_TERMINATED,this.emit("referRejected",this),this.referredSession&&this.referredSession.emit("referRejected")}};this.targetSession.once("rejected",o.bind(this)),this.targetSession.once("failed",o.bind(this))}else this.logger.log("Accepted refer, but did not automatically follow it"),this.sendNotify("SIP/2.0 200 OK"),this.emit("referAccepted",this),this.referredSession&&this.referredSession.emit("referAccepted",this)},sendNotify:function(t){if(this.status!==c.STATUS_ANSWERED)throw new e.Exceptions.InvalidStateError(this.status);if(-1===e.Grammar.parse(t,"sipfrag"))throw new Error("sipfrag body is required to send notify for refer");var i=new e.OutgoingRequest(e.C.NOTIFY,this.remote_target,this.ua,{cseq:this.cseq+=1,call_id:this.call_id,from_uri:this.from_uri,from_tag:this.from_tag,to_uri:this.to_uri,to_tag:this.to_tag,route_set:this.route_set},["Event: refer","Subscription-State: terminated","Content-Type: message/sipfrag"],t);new e.RequestSender({request:i,onRequestTimeout:function(){},onTransportError:function(){},receiveResponse:function(){}},this.ua).send()}},e.ReferServerContext=n}},function(e,t,i){"use strict";e.exports=function(e){var t;return t=function(i,s,r){var n,o;if(void 0===s)throw new TypeError("Not enough arguments");if(this.logger=i.ua.getLogger("sip.invitecontext.dtmf",i.id),this.owner=i,this.direction=null,r=r||{},n=r.duration||null,o=r.interToneGap||null,"string"==typeof s)s=s.toUpperCase();else{if("number"!=typeof s)throw new TypeError("Invalid tone: "+s);s=s.toString()}if(!s.match(/^[0-9A-D#*]$/))throw new TypeError("Invalid tone: "+s);if(this.tone=s,n&&!e.Utils.isDecimal(n))throw new TypeError("Invalid tone duration: "+n);if(n?nt.C.MAX_DURATION?(this.logger.warn('"duration" value is greater than the maximum allowed, setting it to '+t.C.MAX_DURATION+" milliseconds"),n=t.C.MAX_DURATION):n=Math.abs(n):n=t.C.DEFAULT_DURATION,this.duration=n,o&&!e.Utils.isDecimal(o))throw new TypeError("Invalid interToneGap: "+o);o?o=300||"notify_wait"!==this.state&&-1!==this.errorCodes.indexOf(t.status_code)?this.failed(t,null):/^2[0-9]{2}$/.test(t.status_code)?(this.emit("accepted",t,s),(i=t.getHeader("Expires"))&&i<=this.requestedExpires?(this.expires=i,this.timers.sub_duration=e.Timers.setTimeout(this.refresh.bind(this),900*i)):i?(this.logger.warn("Expires header in a 200-class response to SUBSCRIBE with a higher value than the one in the request"),this.failed(t,e.C.INVALID_EXPIRES_HEADER)):(this.logger.warn("Expires header missing in a 200-class response to SUBSCRIBE"),this.failed(t,e.C.EXPIRES_HEADER_MISSING))):t.statusCode>300&&(this.emit("failed",t,s),this.emit("rejected",t,s))},unsubscribe:function(){var t=[];this.state="terminated",t.push("Event: "+this.event),t.push("Expires: 0"),t.push("Contact: "+this.contact),t.push("Allow: "+e.UA.C.ALLOWED_METHODS.toString()),this.receiveResponse=function(){},this.dialog.sendRequest(this,this.method,{extraHeaders:t,body:this.body}),e.Timers.clearTimeout(this.timers.sub_duration),e.Timers.clearTimeout(this.timers.N),this.timers.N=e.Timers.setTimeout(this.timer_fire.bind(this),e.Timers.TIMER_N)},timer_fire:function(){"terminated"===this.state?(this.terminateDialog(),e.Timers.clearTimeout(this.timers.N),e.Timers.clearTimeout(this.timers.sub_duration),delete this.ua.subscriptions[this.id]):"notify_wait"===this.state||"pending"===this.state?this.close():this.refresh()},close:function(){"notify_wait"===this.state?(this.state="terminated",e.Timers.clearTimeout(this.timers.N),e.Timers.clearTimeout(this.timers.sub_duration),this.receiveResponse=function(){},delete this.ua.earlySubscriptions[this.request.call_id+this.request.from.parameters.tag+this.event]):"terminated"!==this.state&&this.unsubscribe()},createConfirmedDialog:function(t,i){var s;return this.terminateDialog(),s=new e.Dialog(this,t,i),s.invite_seqnum=this.request.cseq,s.local_seqnum=this.request.cseq,!s.error&&(this.dialog=s,!0)},terminateDialog:function(){this.dialog&&(delete this.ua.subscriptions[this.id],this.dialog.terminate(),delete this.dialog)},receiveRequest:function(t){function i(){s.expires&&(e.Timers.clearTimeout(r.timers.sub_duration),s.expires=Math.min(r.expires,Math.max(s.expires,0)),r.timers.sub_duration=e.Timers.setTimeout(r.refresh.bind(r),900*s.expires))}var s,r=this;if(this.matchEvent(t))if(this.dialog||this.createConfirmedDialog(t,"UAS")&&(this.id=this.dialog.id.toString(),delete this.ua.earlySubscriptions[this.request.call_id+this.request.from.parameters.tag+this.event],this.ua.subscriptions[this.id]=this),s=t.parseHeader("Subscription-State"),t.reply(200,e.C.REASON_200),e.Timers.clearTimeout(this.timers.N),this.emit("notify",{request:t}),"terminated"!==this.state)switch(s.state){case"active":this.state="active",i();break;case"pending":"notify_wait"===this.state&&i(),this.state="pending";break;case"terminated":if(e.Timers.clearTimeout(this.timers.sub_duration),s.reason)switch(this.logger.log("terminating subscription with reason "+s.reason),s.reason){case"deactivated":case"timeout":return void this.subscribe();case"probation":case"giveup":return void(s.params&&s.params["retry-after"]?this.timers.sub_duration=e.Timers.setTimeout(r.subscribe.bind(r),s.params["retry-after"]):this.subscribe())}this.close()}else"terminated"===s.state&&(this.terminateDialog(),e.Timers.clearTimeout(this.timers.N),e.Timers.clearTimeout(this.timers.sub_duration),delete this.ua.subscriptions[this.id]);else t.reply(489)},failed:function(e,t){return this.close(),this.emit("failed",e,t),this.emit("rejected",e,t),this},onDialogError:function(t){this.failed(t,e.C.causes.DIALOG_ERROR)},matchEvent:function(e){var t;return e.hasHeader("Event")?e.hasHeader("Subscription-State")?(t=e.parseHeader("event").event,this.event===t||(this.logger.warn("event match failed"),e.reply(481,"Event Match Failed"),!1)):(this.logger.warn("missing Subscription-State header"),!1):(this.logger.warn("missing Event header"),!1)}}}},function(e,t,i){"use strict";(function(t){var s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};e.exports=function(e,r){function n(t){if(t instanceof Function)return t.initialize||(t.initialize=function(){return e.Utils.Promise.resolve()}),t}var o,a={STATUS_INIT:0,STATUS_STARTING:1,STATUS_READY:2,STATUS_USER_CLOSED:3,STATUS_NOT_READY:4,CONFIGURATION_ERROR:1,NETWORK_ERROR:2,ALLOWED_METHODS:["ACK","CANCEL","INVITE","MESSAGE","BYE","OPTIONS","INFO","NOTIFY","REFER"],ACCEPTED_BODY_TYPES:["application/sdp","application/dtmf-relay"],MAX_FORWARDS:70,TAG_LENGTH:10};((o=function(t){function i(e){return s.emit.bind(s,e)}var s=this;a.ACCEPTED_BODY_TYPES=a.ACCEPTED_BODY_TYPES.toString(),this.log=new e.LoggerFactory,this.logger=this.getLogger("sip.ua"),this.cache={credentials:{}},this.configuration={},this.dialogs={},this.applicants={},this.data={},this.sessions={},this.subscriptions={},this.earlySubscriptions={},this.transport=null,this.contact=null,this.status=a.STATUS_INIT,this.error=null,this.transactions={nist:{},nict:{},ist:{},ict:{}},this.transportRecoverAttempts=0,this.transportRecoveryTimer=null,Object.defineProperties(this,{transactionsCount:{get:function(){var e,t=["nist","nict","ist","ict"],i=0;for(e in t)i+=Object.keys(this.transactions[t[e]]).length;return i}},nictTransactionsCount:{get:function(){return Object.keys(this.transactions.nict).length}},nistTransactionsCount:{get:function(){return Object.keys(this.transactions.nist).length}},ictTransactionsCount:{get:function(){return Object.keys(this.transactions.ict).length}},istTransactionsCount:{get:function(){return Object.keys(this.transactions.ist).length}}}),void 0===t?t={}:("string"==typeof t||t instanceof String)&&(t={uri:t}),t.log&&(t.log.hasOwnProperty("builtinEnabled")&&(this.log.builtinEnabled=t.log.builtinEnabled),t.log.hasOwnProperty("level")&&(this.log.level=t.log.level),t.log.hasOwnProperty("connector")&&(this.log.connector=t.log.connector));try{this.loadConfig(t)}catch(e){throw this.status=a.STATUS_NOT_READY,this.error=a.CONFIGURATION_ERROR,e}this.registerContext=new e.RegisterContext(this),this.registerContext.on("failed",i("registrationFailed")),this.registerContext.on("registered",i("registered")),this.registerContext.on("unregistered",i("unregistered")),this.configuration.autostart&&this.start()}).prototype=Object.create(e.EventEmitter.prototype)).register=function(e){return this.configuration.register=!0,this.registerContext.register(e),this},o.prototype.unregister=function(e){this.configuration.register=!1;var t=this.registerContext;return this.afterConnected(t.unregister.bind(t,e)),this},o.prototype.isRegistered=function(){return this.registerContext.registered},o.prototype.isConnected=function(){return!!this.transport&&this.transport.connected},o.prototype.afterConnected=function(e){this.isConnected()?e():this.once("connected",e)},o.prototype.waitForConnected=function(){return new e.Utils.Promise(function(e){this.afterConnected(e)}.bind(this))},o.prototype.invite=function(t,i,s){var r=new e.InviteClientContext(this,t,i,s);return this.waitForConnected().then(function(){r.invite(),this.emit("inviteSent",r)}.bind(this)),r},o.prototype.subscribe=function(t,i,s){var r=new e.Subscription(this,t,i,s);return this.afterConnected(r.subscribe.bind(r)),r},o.prototype.message=function(t,i,s){if(void 0===i)throw new TypeError("Not enough arguments");return(s=Object.create(s||Object.prototype)).contentType||(s.contentType="text/plain"),s.body=i,this.request(e.C.MESSAGE,t,s)},o.prototype.request=function(t,i,s){var r=new e.ClientContext(this,t,i,s);return this.afterConnected(r.send.bind(r)),r},o.prototype.stop=function(){function i(){0===c.nistTransactionsCount&&0===c.nictTransactionsCount&&(c.removeListener("transactionDestroyed",i),c.transport.disconnect())}var s,n,o,c=this;if(this.logger.log("user requested closure..."),this.status===a.STATUS_USER_CLOSED)return this.logger.warn("UA already closed"),this;e.Timers.clearTimeout(this.transportRecoveryTimer),this.logger.log("closing registerContext"),this.registerContext.close();for(s in this.sessions)this.logger.log("closing session "+s),this.sessions[s].terminate();for(n in this.subscriptions)this.logger.log("unsubscribing from subscription "+n),this.subscriptions[n].close();for(n in this.earlySubscriptions)this.logger.log("unsubscribing from early subscription "+n),this.earlySubscriptions[n].close();for(o in this.applicants)this.applicants[o].close();return this.status=a.STATUS_USER_CLOSED,0===this.nistTransactionsCount&&0===this.nictTransactionsCount?this.transport.disconnect():this.on("transactionDestroyed",i),"function"==typeof r.removeEventListener&&(t.chrome&&t.chrome.app&&t.chrome.app.runtime||r.removeEventListener("unload",this.environListener)),this},o.prototype.start=function(){var i;return this.logger.log("user requested startup..."),this.status===a.STATUS_INIT?(i=this.getNextWsServer(),this.status=a.STATUS_STARTING,new e.Transport(this,i)):this.status===a.STATUS_USER_CLOSED?(this.logger.log("resuming"),this.status=a.STATUS_READY,this.transport.connect()):this.status===a.STATUS_STARTING?this.logger.log("UA is in STARTING status, not opening new connection"):this.status===a.STATUS_READY?this.logger.log("UA is in READY status, not resuming"):this.logger.error("Connection is down. Auto-Recovery system is trying to connect"),this.configuration.autostop&&"function"==typeof r.addEventListener&&(t.chrome&&t.chrome.app&&t.chrome.app.runtime||(this.environListener=this.stop.bind(this),r.addEventListener("unload",this.environListener))),this},o.prototype.normalizeTarget=function(t){return e.Utils.normalizeTarget(t,this.configuration.hostportParams)},o.prototype.saveCredentials=function(e){return this.cache.credentials[e.realm]=this.cache.credentials[e.realm]||{},this.cache.credentials[e.realm][e.uri]=e,this},o.prototype.getCredentials=function(e){var t,i;return t=e.ruri.host,this.cache.credentials[t]&&this.cache.credentials[t][e.ruri]&&((i=this.cache.credentials[t][e.ruri]).method=e.method),i},o.prototype.getLogger=function(e,t){return this.log.getLogger(e,t)},o.prototype.onTransportClosed=function(t){var i,s,r,n=["nict","ict","nist","ist"];for(t.server.status=e.Transport.C.STATUS_DISCONNECTED,this.logger.log("connection state set to "+e.Transport.C.STATUS_DISCONNECTED),r=n.length,i=0;i0?(t.reply(200,null),this.emit("notify",{request:t})):t.reply(481,"Subscription does not exist");break;case e.C.REFER:if(this.logger.log("Received an out of dialog refer"),this.configuration.allowOutOfDialogRefers){this.logger.log("Allow out of dialog refers is enabled on the UA");var l=new e.ReferServerContext(this,t);this.listeners("outOfDialogReferRequested").length?this.emit("outOfDialogReferRequested",l):(this.logger.log("No outOfDialogReferRequest listeners, automatically accepting and following the out of dialog refer"),l.accept({followRefer:!0}));break}t.reply(405);break;default:t.reply(405)}}else t.reply_sl(416)},o.prototype.findSession=function(e){return this.sessions[e.call_id+e.from_tag]||this.sessions[e.call_id+e.to_tag]||null},o.prototype.findDialog=function(e){return this.dialogs[e.call_id+e.from_tag+e.to_tag]||this.dialogs[e.call_id+e.to_tag+e.from_tag]||null},o.prototype.findEarlySubscription=function(e){return this.earlySubscriptions[e.call_id+e.to_tag+e.getHeader("event")]||null},o.prototype.getNextWsServer=function(){var t,i,s,r=[];for(i=this.configuration.wsServers.length,t=0;tr[0].weight?r=[s]:s.weight===r[0].weight&&r.push(s));return t=Math.floor(Math.random()*r.length),r[t]},o.prototype.closeSessionsOnTransportError=function(){var e;for(e in this.sessions)this.sessions[e].onTransportError();this.registerContext.onTransportClosed()},o.prototype.recoverTransport=function(t){var i,s,r,n,o;for(n=(t=t||this).transportRecoverAttempts,s=t.configuration.wsServers.length,i=0;it.configuration.connectionRecoveryMaxInterval&&(this.logger.log("time for next connection attempt exceeds connectionRecoveryMaxInterval, resetting counter"),r=t.configuration.connectionRecoveryMinInterval,n=0),this.logger.log("next connection attempt in "+r+" seconds"),this.transportRecoveryTimer=e.Timers.setTimeout(function(){t.transportRecoverAttempts=n+1,new e.Transport(t,o)},1e3*r)},o.prototype.loadConfig=function(t){function s(e,i){var s=e.replace(/([a-z][A-Z])/g,function(e){return e[0]+"_"+e[1].toLowerCase()});if(e!==s){var r=t.hasOwnProperty(e);t.hasOwnProperty(s)&&(i.warn(s+" is deprecated, please use "+e),r&&i.warn(e+" overriding "+s)),t[e]=r?t[e]:t[s]}}var r,o,a,c,h,u={viaHost:e.Utils.createRandomToken(12)+".invalid",uri:new e.URI("sip","anonymous."+e.Utils.createRandomToken(6),"anonymous.invalid",null,null),wsServers:[{scheme:"WSS",sip_uri:"",status:0,weight:0,ws_uri:"wss://edge.sip.onsip.com"}],custom:{},displayName:"",password:null,registerExpires:600,register:!0,registrarServer:null,wsServerMaxReconnection:3,wsServerReconnectionTimeout:4,connectionRecoveryMinInterval:2,connectionRecoveryMaxInterval:30,keepAliveInterval:0,extraSupported:[],usePreloadedRoute:!1,userAgentString:e.C.USER_AGENT,noAnswerTimeout:60,traceSip:!1,hackViaTcp:!1,hackIpInContact:!1,hackWssInTransport:!1,hackAllowUnregisteredOptionTags:!1,sessionDescriptionHandlerFactoryOptions:{constraints:{},peerConnectionOptions:{}},contactName:e.Utils.createRandomToken(8),contactTransport:"ws",forceRport:!1,autostart:!0,autostop:!0,rel100:e.C.supported.UNSUPPORTED,replaces:e.C.supported.UNSUPPORTED,sessionDescriptionHandlerFactory:i(27)(e).defaultFactory,authenticationFactory:n(function(t){return new e.DigestAuthentication(t)}),allowLegacyNotifications:!1,allowOutOfDialogRefers:!1},l=this.getConfigurationCheck();for(r in l.mandatory){if(s(r,this.logger),!t.hasOwnProperty(r))throw new e.Exceptions.ConfigurationError(r);if(o=t[r],void 0===(a=l.mandatory[r](o)))throw new e.Exceptions.ConfigurationError(r,o);u[r]=a}for(r in l.optional)if(s(r,this.logger),t.hasOwnProperty(r)){if((o=t[r])instanceof Array&&0===o.length)continue;if(null===o||""===o||void 0===o)continue;if("number"==typeof o&&isNaN(o))continue;if(void 0===(a=l.optional[r](o)))throw new e.Exceptions.ConfigurationError(r,o);u[r]=a}if(u.connectionRecoveryMaxInterval"}};var d={};for(r in u)d[r]={value:u[r],writable:"register"===r||"custom"===r,configurable:!1};Object.defineProperties(this.configuration,d),this.logger.log("configuration parameters after validation:");for(r in u)switch(r){case"uri":case"registrarServer":case"sessionDescriptionHandlerFactory":this.logger.log("\xb7 "+r+": "+u[r]);break;case"password":this.logger.log("\xb7 "+r+": NOT SHOWN");break;default:this.logger.log("\xb7 "+r+": "+JSON.stringify(u[r]))}},o.prototype.getConfigurationCheck=function(){return{mandatory:{},optional:{uri:function(t){var i;return/^sip:/i.test(t)||(t=e.C.SIP+":"+t),(i=e.URI.parse(t))&&i.user?i:void 0},wsServers:function(t){var i,s,r;if("string"==typeof t)t=[{ws_uri:t}];else{if(!(t instanceof Array))return;for(s=t.length,i=0;i",t[i].weight||(t[i].weight=0),t[i].status=0,t[i].scheme=r.scheme.toUpperCase()}return t},authorizationUser:function(t){return-1===e.Grammar.parse('"'+t+'"',"quoted_string")?void 0:t},connectionRecoveryMaxInterval:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},connectionRecoveryMinInterval:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},displayName:function(t){return-1===e.Grammar.parse('"'+t+'"',"displayName")?void 0:t},hackViaTcp:function(e){if("boolean"==typeof e)return e},hackIpInContact:function(t){return"boolean"==typeof t?t:"string"==typeof t&&-1!==e.Grammar.parse(t,"host")?t:void 0},hackWssInTransport:function(e){if("boolean"==typeof e)return e},hackAllowUnregisteredOptionTags:function(e){if("boolean"==typeof e)return e},contactTransport:function(e){if("string"==typeof e)return e},forceRport:function(e){if("boolean"==typeof e)return e},instanceId:function(t){if("string"==typeof t)return/^uuid:/i.test(t)&&(t=t.substr(5)),-1===e.Grammar.parse(t,"uuid")?void 0:t},keepAliveInterval:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},extraSupported:function(e){var t,i;if(e instanceof Array){for(i=e.length,t=0;t0)return i},password:function(e){return String(e)},rel100:function(t){return t===e.C.supported.REQUIRED?e.C.supported.REQUIRED:t===e.C.supported.SUPPORTED?e.C.supported.SUPPORTED:e.C.supported.UNSUPPORTED},replaces:function(t){return t===e.C.supported.REQUIRED?e.C.supported.REQUIRED:t===e.C.supported.SUPPORTED?e.C.supported.SUPPORTED:e.C.supported.UNSUPPORTED},register:function(e){if("boolean"==typeof e)return e},registerExpires:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},registrarServer:function(t){var i;if("string"==typeof t)return/^sip:/i.test(t)||(t=e.C.SIP+":"+t),(i=e.URI.parse(t))?i.user?void 0:i:void 0},traceSip:function(e){if("boolean"==typeof e)return e},userAgentString:function(e){if("string"==typeof e)return e},usePreloadedRoute:function(e){if("boolean"==typeof e)return e},wsServerMaxReconnection:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},wsServerReconnectionTimeout:function(t){var i;if(e.Utils.isDecimal(t)&&(i=Number(t))>0)return i},autostart:function(e){if("boolean"==typeof e)return e},autostop:function(e){if("boolean"==typeof e)return e},sessionDescriptionHandlerFactory:function(e){if(e instanceof Function)return e},sessionDescriptionHandlerFactoryOptions:function(e){if("object"===(void 0===e?"undefined":s(e)))return e},authenticationFactory:n,allowLegacyNotifications:function(e){if("boolean"==typeof e)return e},custom:function(e){if("object"===(void 0===e?"undefined":s(e)))return e},contactName:function(e){if("string"==typeof e)return e}}}},o.C=a,e.UA=o}}).call(t,i(0))},function(e,t,i){"use strict";(function(t){e.exports=function(e){var i=function(e,i){this.options=i||{},this.logger=e.ua.getLogger("sip.invitecontext.sessionDescriptionHandler",e.id),this.session=e,this.CONTENT_TYPE="application/sdp",this.modifiers=this.options.modifiers||[],Array.isArray(this.modifiers)||(this.modifiers=[this.modifiers]);var s=t.window||t;this.WebRTC={MediaStream:s.MediaStream,getUserMedia:s.navigator.mediaDevices.getUserMedia.bind(s.navigator.mediaDevices),RTCPeerConnection:s.RTCPeerConnection,RTCSessionDescription:s.RTCSessionDescription},this.iceGatheringDeferred=null,this.iceGatheringTimeout=!1,this.iceGatheringTimer=null,this.initPeerConnection(this.options.peerConnectionOptions),this.constraints=this.checkAndDefaultConstraints(this.options.constraints),this.session.emit("SessionDescriptionHandler-created",this)};return i.defaultFactory=function(e,t){return new i(e,t)},i.prototype=Object.create(e.SessionDescriptionHandler.prototype,{close:{writable:!0,value:function(){this.logger.log("closing PeerConnection"),this.peerConnection&&"closed"!==this.peerConnection.signalingState&&(this.peerConnection.getSenders?this.peerConnection.getSenders().forEach(function(e){e.track&&e.track.stop()}):(this.logger.warn("Using getLocalStreams which is deprecated"),this.peerConnection.getLocalStreams().forEach(function(e){e.getTracks().forEach(function(e){e.stop()})})),this.peerConnection.getReceivers?this.peerConnection.getReceivers().forEach(function(e){e.track&&e.track.stop()}):(this.logger.warn("Using getRemoteStreams which is deprecated"),this.peerConnection.getRemoteStreams().forEach(function(e){e.getTracks().forEach(function(e){e.stop()})})),this.resetIceGatheringComplete(),this.peerConnection.close())}},getDescription:{writable:!0,value:function(t,i){var s=this,r=!0;if(this.session.disableRenegotiation)return this.logger.warn('The flag "disableRenegotiation" is set to true for this session description handler. We will not try to renegotiate.'),e.Utils.Promise.reject(new e.Exceptions.RenegotiationError("disableRenegotiation flag set to true for this session description handler"));(t=t||{}).peerConnectionOptions&&this.initPeerConnection(t.peerConnectionOptions);var n=Object.assign({},this.constraints,t.constraints);return n=this.checkAndDefaultConstraints(n),JSON.stringify(n)!==JSON.stringify(this.constraints)?this.constraints=n:r=!1,i=i||[],Array.isArray(i)||(i=[i]),i=i.concat(this.modifiers),!r&&this.peerConnection.localDescription&&this.peerConnection.localDescription.sdp&&""!==this.peerConnection.localDescription.sdp?this.createOfferOrAnswer(t.RTCOfferOptions,i).then(function(e){return{body:e,contentType:s.CONTENT_TYPE}}):(s.logger.log("acquiring local media"),this.acquire(s.constraints).then(function(e){return s.logger.log("acquired local media streams"),e},function(e){throw s.logger.error("unable to acquire streams"),s.logger.error(e),e}).then(function(t){try{(t=[].concat(t)).forEach(function(e){s.peerConnection.addTrack?e.getTracks().forEach(function(t){s.peerConnection.addTrack(t,e)}):s.peerConnection.addStream(e)},this)}catch(t){return s.logger.error("error adding stream"),s.logger.error(t),e.Utils.Promise.reject(t)}return e.Utils.Promise.resolve()}).then(function(){return s.createOfferOrAnswer(t.RTCOfferOptions,i)}).then(function(e){return{body:e,contentType:s.CONTENT_TYPE}}).catch(function(e){throw this.session.disableRenegotiation=!0,e}))}},hasDescription:{writable:!0,value:function(e){return e===this.CONTENT_TYPE}},holdModifier:{writable:!0,value:function(t){return/a=(sendrecv|sendonly|recvonly|inactive)/.test(t.sdp)?(t.sdp=t.sdp.replace(/a=sendrecv\r\n/g,"a=sendonly\r\n"),t.sdp=t.sdp.replace(/a=recvonly\r\n/g,"a=inactive\r\n")):t.sdp=t.sdp.replace(/(m=[^\r]*\r\n)/g,"$1a=sendonly\r\n"),e.Utils.Promise.resolve(t)}},setDescription:{writable:!0,value:function(t,i,s){var r=this,n="undefined"!=typeof InstallTrigger;if(!this.session.disableRenegotiation&&n&&this.peerConnection&&this.isVideoHold(t)&&(this.session.disableRenegotiation=!0),this.session.disableRenegotiation)return this.logger.warn('The flag "disableRenegotiation" is set to true for this session description handler. We will not try to renegotiate.'),e.Utils.Promise.reject(new e.Exceptions.RenegotiationError("disableRenegotiation flag set to true for this session description handler"));(i=i||{}).peerConnectionOptions&&this.initPeerConnection(i.peerConnectionOptions),this.constraints=Object.assign({},this.constraints,i.constraints),this.constraints=this.checkAndDefaultConstraints(this.constraints),s=s||[],Array.isArray(s)||(s=[s]),s=s.concat(this.modifiers);var o={type:this.hasOffer("local")?"answer":"offer",sdp:t};return e.Utils.reducePromises(s,o).catch(function(e){throw r.logger.error("The modifiers did not resolve successfully"),r.logger.error(e),e}).then(function(e){return r.emit("setDescription",e),r.peerConnection.setRemoteDescription(new r.WebRTC.RTCSessionDescription(e))}).catch(function(e){throw r.session.disableRenegotiation=!0,r.logger.error(e),r.emit("peerConnection-setRemoteDescriptionFailed",e),e}).then(function(){r.peerConnection.getReceivers?r.emit("setRemoteDescription",r.peerConnection.getReceivers()):r.emit("setRemoteDescription",r.peerConnection.getRemoteStreams()),r.emit("confirmed",r)})}},createOfferOrAnswer:{writable:!0,value:function(t,i){var s,r=this,n=this.peerConnection;return t=t||{},s=r.hasOffer("remote")?"createAnswer":"createOffer",n[s](t).catch(function(e){throw r.emit("peerConnection-"+s+"Failed",e),e}).then(function(t){return e.Utils.reducePromises(i,t)}).then(function(e){return r.logger.log(e),n.setLocalDescription(e)}).catch(function(e){throw r.emit("peerConnection-SetLocalDescriptionFailed",e),e}).then(function(){return r.waitForIceGatheringComplete()}).then(function(){var t=r.peerConnection.localDescription;return e.Utils.reducePromises(i,t)}).then(function(e){return r.emit("getDescription",e),e.sdp}).catch(function(t){throw r.logger.error(t),new e.Exceptions.GetDescriptionError(t)})}},addDefaultIceCheckingTimeout:{writable:!0,value:function(e){return void 0===e.iceCheckingTimeout&&(e.iceCheckingTimeout=5e3),e}},addDefaultIceServers:{writable:!0,value:function(e){return e.iceServers||(e.iceServers=[{urls:"stun:stun.l.google.com:19302"}]),e}},checkAndDefaultConstraints:{writable:!0,value:function(e){var t={audio:!0,video:!0};return e=e||t,0===Object.keys(e).length&&e.constructor===Object?t:e}},initPeerConnection:{writable:!0,value:function(t){var i=this;t=t||{},(t=this.addDefaultIceCheckingTimeout(t)).rtcConfiguration=t.rtcConfiguration||{},t.rtcConfiguration=this.addDefaultIceServers(t.rtcConfiguration),this.logger.log("initPeerConnection"),this.peerConnection&&(this.logger.log("Already have a peer connection for this session. Tearing down."),this.resetIceGatheringComplete(),this.peerConnection.close()),this.peerConnection=new this.WebRTC.RTCPeerConnection(t.rtcConfiguration),this.logger.log("New peer connection created"),this.session.emit("peerConnection-created",this.peerConnection),this.peerConnection.ontrack=function(e){i.logger.log("track added"),i.emit("addTrack",e)},this.peerConnection.onaddstream=function(e){i.logger.warn("Using deprecated stream API"),i.logger.log("stream added"),i.emit("addStream",e)},this.peerConnection.onremovestream=function(e){i.logger.log("stream removed: "+e.stream.id)},this.peerConnection.onicecandidate=function(e){i.emit("iceCandidate",e),e.candidate&&i.logger.log("ICE candidate received: "+(null===e.candidate.candidate?null:e.candidate.candidate.trim()))},this.peerConnection.onicegatheringstatechange=function(){switch(i.logger.log("RTCIceGatheringState changed: "+this.iceGatheringState),this.iceGatheringState){case"gathering":i.emit("iceGathering",this),!i.iceGatheringTimer&&t.iceCheckingTimeout&&(i.iceGatheringTimeout=!1,i.iceGatheringTimer=e.Timers.setTimeout(function(){i.logger.log("RTCIceChecking Timeout Triggered after "+t.iceCheckingTimeout+" milliseconds"),i.iceGatheringTimeout=!0,i.triggerIceGatheringComplete()},t.iceCheckingTimeout));break;case"complete":i.triggerIceGatheringComplete()}},this.peerConnection.oniceconnectionstatechange=function(){var e;switch(this.iceConnectionState){case"new":e="iceConnection";break;case"checking":e="iceConnectionChecking";break;case"connected":e="iceConnectionConnected";break;case"completed":e="iceConnectionCompleted";break;case"failed":e="iceConnectionFailed";break;case"disconnected":e="iceConnectionDisconnected";break;case"closed":e="iceConnectionClosed";break;default:return void i.logger.warn("Unknown iceConnection state:",this.iceConnectionState)}i.emit(e,this)}}},acquire:{writable:!0,value:function(t){return t=this.checkAndDefaultConstraints(t),new e.Utils.Promise(function(e,i){this.emit("userMediaRequest",t);var s=function(e,t){var i=Array.prototype.slice.call(arguments,2),s=[e].concat(i);return this.emit.apply(this,s),t.apply(null,i)}.bind(this);t.audio||t.video?this.WebRTC.getUserMedia(t).then(s.bind(this,"userMedia",function(t){e(t)}),s.bind(this,"userMediaFailed",function(e){throw i(e),e})):e([])}.bind(this))}},isVideoHold:{writable:!0,value:function(e){return-1!==e.search(/^(m=video.*?)[\s\S]*^(a=sendonly?)/gm)}},hasOffer:{writable:!0,value:function(e){var t="have-"+e+"-offer";return this.peerConnection.signalingState===t}},isIceGatheringComplete:{writable:!0,value:function(){return"complete"===this.peerConnection.iceGatheringState||this.iceGatheringTimeout}},resetIceGatheringComplete:{writable:!0,value:function(){this.iceGatheringTimeout=!1,this.iceGatheringTimer&&(e.Timers.clearTimeout(this.iceGatheringTimer),this.iceGatheringTimer=null),this.iceGatheringDeferred&&(this.iceGatheringDeferred.reject(),this.iceGatheringDeferred=null)}},triggerIceGatheringComplete:{writable:!0,value:function(){this.isIceGatheringComplete()&&(this.emit("iceGatheringComplete",this),this.iceGatheringTimer&&(e.Timers.clearTimeout(this.iceGatheringTimer),this.iceGatheringTimer=null),this.iceGatheringDeferred&&(this.iceGatheringDeferred.resolve(),this.iceGatheringDeferred=null))}},waitForIceGatheringComplete:{writable:!0,value:function(){return this.isIceGatheringComplete()?e.Utils.Promise.resolve():(this.isIceGatheringDeferred||(this.iceGatheringDeferred=e.Utils.defer()),this.iceGatheringDeferred.promise)}}}),i}}).call(t,i(0))},function(e,t,i){"use strict";e.exports=function(e){function t(t,i,s){for(var r,n=e.Utils.buildStatusLine(t),o=i.getHeaders("via"),a=o.length,c=0;c1)return t.getLogger("sip.sanitycheck").warn("More than one Via header field present in the response. Dropping the response"),!1}),r.push(function(e,t){var i=t.configuration.viaHost;if(e.via.host!==i||void 0!==e.via.port)return t.getLogger("sip.sanitycheck").warn("Via sent-by in the response does not match UA Via host value. Dropping the response"),!1}),r.push(function(t,i){if(e.Utils.str_utf8_length(t.body)-1)this.qop="auth";else{if(!(i.qop.indexOf("auth-int")>-1))return this.logger.warn('challenge without Digest qop different than "auth" or "auth-int", authentication aborted'),!1;this.qop="auth-int"}else this.qop=null;return this.method=t.method,this.uri=t.ruri,this.cnonce=e.createRandomToken(12),this.nc+=1,this.updateNcHex(),4294967296===this.nc&&(this.nc=1,this.ncHex="00000001"),this.calculateResponse(),!0},t.prototype.calculateResponse=function(){var t,i;t=e.calculateMD5(this.username+":"+this.realm+":"+this.password),"auth"===this.qop?(i=e.calculateMD5(this.method+":"+this.uri),this.response=e.calculateMD5(t+":"+this.nonce+":"+this.ncHex+":"+this.cnonce+":auth:"+i)):"auth-int"===this.qop?(i=e.calculateMD5(this.method+":"+this.uri+":"+e.calculateMD5(this.body?this.body:"")),this.response=e.calculateMD5(t+":"+this.nonce+":"+this.ncHex+":"+this.cnonce+":auth-int:"+i)):null===this.qop&&(i=e.calculateMD5(this.method+":"+this.uri),this.response=e.calculateMD5(t+":"+this.nonce+":"+i))},t.prototype.toString=function(){var e=[];if(!this.response)throw new Error("response field does not exist, cannot generate Authorization header");return e.push("algorithm="+this.algorithm),e.push('username="'+this.username+'"'),e.push('realm="'+this.realm+'"'),e.push('nonce="'+this.nonce+'"'),e.push('uri="'+this.uri+'"'),e.push('response="'+this.response+'"'),this.opaque&&e.push('opaque="'+this.opaque+'"'),this.qop&&(e.push("qop="+this.qop),e.push('cnonce="'+this.cnonce+'"'),e.push("nc="+this.ncHex)),"Digest "+e.join(", ")},t.prototype.updateNcHex=function(){var e=Number(this.nc).toString(16);this.ncHex="00000000".substr(0,8-e.length)+e},t}},function(e,t,i){"use strict";var s=i(31);e.exports=function(e){return{parse:function(t,i){var r={startRule:i,SIP:e};try{s.parse(t,r)}catch(e){r.data=-1}return r.data}}}},function(e,t,i){"use strict";function s(e,t,i,r){this.message=e,this.expected=t,this.found=i,this.location=r,this.name="SyntaxError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,s)}!function(e,t){function i(){this.constructor=e}i.prototype=t.prototype,e.prototype=new i}(s,Error),s.buildMessage=function(e,t){function i(e){return e.charCodeAt(0).toString(16).toUpperCase()}function s(e){return e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(e){return"\\x0"+i(e)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(e){return"\\x"+i(e)})}function r(e){return e.replace(/\\/g,"\\\\").replace(/\]/g,"\\]").replace(/\^/g,"\\^").replace(/-/g,"\\-").replace(/\0/g,"\\0").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\x00-\x0F]/g,function(e){return"\\x0"+i(e)}).replace(/[\x10-\x1F\x7F-\x9F]/g,function(e){return"\\x"+i(e)})}function n(e){return o[e.type](e)}var o={literal:function(e){return'"'+s(e.text)+'"'},class:function(e){var t,i="";for(t=0;t0){for(t=1,i=1;tR&&(R=E,v=[]),v.push(e))}function u(e,t,i){return new s(s.buildMessage(e,t),e,t,i)}function l(e){var t,i=new Array(e.length);for(t=0;tE?(a=n+3+r[n+1],n+=3):(a=n+3+r[n+1]+r[n+2],n+=3+r[n+1]);break;case 18:c.push(a),o.push(n+4+r[n+2]+r[n+3]),e.substr(E,m[r[n+1]].length)===m[r[n+1]]?(a=n+4+r[n+2],n+=4):(a=n+4+r[n+2]+r[n+3],n+=4+r[n+2]);break;case 19:c.push(a),o.push(n+4+r[n+2]+r[n+3]),e.substr(E,m[r[n+1]].length).toLowerCase()===m[r[n+1]]?(a=n+4+r[n+2],n+=4):(a=n+4+r[n+2]+r[n+3],n+=4+r[n+2]);break;case 20:c.push(a),o.push(n+4+r[n+2]+r[n+3]),m[r[n+1]].test(e.charAt(E))?(a=n+4+r[n+2],n+=4):(a=n+4+r[n+2]+r[n+3],n+=4+r[n+2]);break;case 21:u.push(e.substr(E,r[n+1])),E+=r[n+1],n+=2;break;case 22:u.push(m[r[n+1]]),E+=m[r[n+1]].length,n+=2;break;case 23:u.push(g),0===A&&h(m[r[n+1]]),n+=2;break;case 24:S=u[u.length-1-r[n+1]],n+=2;break;case 25:S=E,n++;break;case 26:for(i=r.slice(n+4,n+4+r[n+3]),s=0;s0))break;a=c.pop(),n=o.pop()}return u[0]}t=void 0!==t?t:{};var p,g={},f={Contact:118,Name_Addr_Header:155,Record_Route:175,Request_Response:81,SIP_URI:45,Subscription_State:185,Supported:190,Require:181,Via:193,absoluteURI:84,Call_ID:117,Content_Disposition:129,Content_Length:134,Content_Type:135,CSeq:145,displayName:121,Event:148,From:150,host:52,Max_Forwards:153,Min_SE:212,Proxy_Authenticate:156,quoted_string:40,Refer_To:177,Replaces:178,Session_Expires:209,stun_URI:216,To:191,turn_URI:222,uuid:225,WWW_Authenticate:208,challenge:157,sipfrag:229,Referred_By:230},T=118,m=["\r\n",n("\r\n",!1),/^[0-9]/,o([["0","9"]],!1,!1),/^[a-zA-Z]/,o([["a","z"],["A","Z"]],!1,!1),/^[0-9a-fA-F]/,o([["0","9"],["a","f"],["A","F"]],!1,!1),/^[\0-\xFF]/,o([["\0","\xff"]],!1,!1),/^["]/,o(['"'],!1,!1)," ",n(" ",!1),"\t",n("\t",!1),/^[a-zA-Z0-9]/,o([["a","z"],["A","Z"],["0","9"]],!1,!1),";",n(";",!1),"/",n("/",!1),"?",n("?",!1),":",n(":",!1),"@",n("@",!1),"&",n("&",!1),"=",n("=",!1),"+",n("+",!1),"$",n("$",!1),",",n(",",!1),"-",n("-",!1),"_",n("_",!1),".",n(".",!1),"!",n("!",!1),"~",n("~",!1),"*",n("*",!1),"'",n("'",!1),"(",n("(",!1),")",n(")",!1),"%",n("%",!1),function(){return" "},function(){return":"},/^[!-~]/,o([["!","~"]],!1,!1),/^[\x80-\uFFFF]/,o([["\x80","\uffff"]],!1,!1),/^[\x80-\xBF]/,o([["\x80","\xbf"]],!1,!1),/^[a-f]/,o([["a","f"]],!1,!1),"`",n("`",!1),"<",n("<",!1),">",n(">",!1),"\\",n("\\",!1),"[",n("[",!1),"]",n("]",!1),"{",n("{",!1),"}",n("}",!1),function(){return"*"},function(){return"/"},function(){return"="},function(){return"("},function(){return")"},function(){return">"},function(){return"<"},function(){return","},function(){return";"},function(){return":"},function(){return'"'},/^[!-']/,o([["!","'"]],!1,!1),/^[*-[]/,o([["*","["]],!1,!1),/^[\]-~]/,o([["]","~"]],!1,!1),function(e){return e},/^[#-[]/,o([["#","["]],!1,!1),/^[\0-\t]/,o([["\0","\t"]],!1,!1),/^[\x0B-\f]/,o([["\v","\f"]],!1,!1),/^[\x0E-\x7F]/,o([["\x0e","\x7f"]],!1,!1),function(){t.data.uri=new t.SIP.URI(t.data.scheme,t.data.user,t.data.host,t.data.port),delete t.data.scheme,delete t.data.user,delete t.data.host,delete t.data.host_type,delete t.data.port},function(){t.data.uri=new t.SIP.URI(t.data.scheme,t.data.user,t.data.host,t.data.port,t.data.uri_params,t.data.uri_headers),delete t.data.scheme,delete t.data.user,delete t.data.host,delete t.data.host_type,delete t.data.port,delete t.data.uri_params,"SIP_URI"===t.startRule&&(t.data=t.data.uri)},"sips",n("sips",!0),"sip",n("sip",!0),function(e){t.data.scheme=e},function(){t.data.user=decodeURIComponent(i().slice(0,-1))},function(){t.data.password=i()},function(){return t.data.host=i(),t.data.host},function(){return t.data.host_type="domain",i()},/^[a-zA-Z0-9_\-]/,o([["a","z"],["A","Z"],["0","9"],"_","-"],!1,!1),/^[a-zA-Z0-9\-]/,o([["a","z"],["A","Z"],["0","9"],"-"],!1,!1),function(){return t.data.host_type="IPv6",i()},"::",n("::",!1),function(){return t.data.host_type="IPv6",i()},function(){return t.data.host_type="IPv4",i()},"25",n("25",!1),/^[0-5]/,o([["0","5"]],!1,!1),"2",n("2",!1),/^[0-4]/,o([["0","4"]],!1,!1),"1",n("1",!1),/^[1-9]/,o([["1","9"]],!1,!1),function(e){return e=parseInt(e.join("")),t.data.port=e,e},"transport=",n("transport=",!0),"udp",n("udp",!0),"tcp",n("tcp",!0),"sctp",n("sctp",!0),"tls",n("tls",!0),function(e){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.transport=e.toLowerCase()},"user=",n("user=",!0),"phone",n("phone",!0),"ip",n("ip",!0),function(e){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.user=e.toLowerCase()},"method=",n("method=",!0),function(e){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.method=e},"ttl=",n("ttl=",!0),function(e){t.data.params||(t.data.params={}),t.data.params.ttl=e},"maddr=",n("maddr=",!0),function(e){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.maddr=e},"lr",n("lr",!0),function(){t.data.uri_params||(t.data.uri_params={}),t.data.uri_params.lr=void 0},function(e,i){t.data.uri_params||(t.data.uri_params={}),i=null===i?void 0:i[1],t.data.uri_params[e.toLowerCase()]=i&&i.toLowerCase()},function(e,i){e=e.join("").toLowerCase(),i=i.join(""),t.data.uri_headers||(t.data.uri_headers={}),t.data.uri_headers[e]?t.data.uri_headers[e].push(i):t.data.uri_headers[e]=[i]},function(){"Refer_To"===t.startRule&&(t.data.uri=new t.SIP.URI(t.data.scheme,t.data.user,t.data.host,t.data.port,t.data.uri_params,t.data.uri_headers),delete t.data.scheme,delete t.data.user,delete t.data.host,delete t.data.host_type,delete t.data.port,delete t.data.uri_params)},"//",n("//",!1),function(){t.data.scheme=i()},n("SIP",!0),function(){t.data.sip_version=i()},"INVITE",n("INVITE",!1),"ACK",n("ACK",!1),"VXACH",n("VXACH",!1),"OPTIONS",n("OPTIONS",!1),"BYE",n("BYE",!1),"CANCEL",n("CANCEL",!1),"REGISTER",n("REGISTER",!1),"SUBSCRIBE",n("SUBSCRIBE",!1),"NOTIFY",n("NOTIFY",!1),"REFER",n("REFER",!1),function(){return t.data.method=i(),t.data.method},function(e){t.data.status_code=parseInt(e.join(""))},function(){t.data.reason_phrase=i()},function(){t.data=i()},function(){var e,i;for(i=t.data.multi_header.length,e=0;e""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E'),l(";).# &;,"),l('2F""6F7G.} &2H""6H7I.q &2J""6J7K.e &2L""6L7M.Y &2N""6N7O.M &2P""6P7Q.A &2R""6R7S.5 &2T""6T7U.) &2V""6V7W'),l('%%2X""6X7Y/5#;#/,$;#/#$+#)(#\'#("\'#&\'#/"!&,)'),l('%%$;$0#*;$&/,#; /#$+")("\'#&\'#." &"/=#$;$/�#*;$&&&#/\'$8":Z" )("\'#&\'#'),l(';.." &"'),l("%$;'.# &;(0)*;'.# &;(&/?#28\"\"6879/0$;//'$8#:[# )(#'#(\"'#&'#"),l('%%$;2/�#*;2&&&#/g#$%$;.0#*;.&/,#;2/#$+")("\'#&\'#0=*%$;.0#*;.&/,#;2/#$+")("\'#&\'#&/#$+")("\'#&\'#/"!&,)'),l('4\\""5!7].# &;3'),l('4^""5!7_'),l('4`""5!7a'),l(';!.) &4b""5!7c'),l('%$;).\x95 &2F""6F7G.\x89 &2J""6J7K.} &2L""6L7M.q &2X""6X7Y.e &2P""6P7Q.Y &2H""6H7I.M &2@""6@7A.A &2d""6d7e.5 &2R""6R7S.) &2N""6N7O/\x9e#0\x9b*;).\x95 &2F""6F7G.\x89 &2J""6J7K.} &2L""6L7M.q &2X""6X7Y.e &2P""6P7Q.Y &2H""6H7I.M &2@""6@7A.A &2d""6d7e.5 &2R""6R7S.) &2N""6N7O&&&#/"!&,)'),l('%$;).\x89 &2F""6F7G.} &2L""6L7M.q &2X""6X7Y.e &2P""6P7Q.Y &2H""6H7I.M &2@""6@7A.A &2d""6d7e.5 &2R""6R7S.) &2N""6N7O/\x92#0\x8f*;).\x89 &2F""6F7G.} &2L""6L7M.q &2X""6X7Y.e &2P""6P7Q.Y &2H""6H7I.M &2@""6@7A.A &2d""6d7e.5 &2R""6R7S.) &2N""6N7O&&&#/"!&,)'),l('2T""6T7U.\xe3 &2V""6V7W.\xd7 &2f""6f7g.\xcb &2h""6h7i.\xbf &2:""6:7;.\xb3 &2D""6D7E.\xa7 &22""6273.\x9b &28""6879.\x8f &2j""6j7k.\x83 &;&.} &24""6475.q &2l""6l7m.e &2n""6n7o.Y &26""6677.M &2>""6>7?.A &2p""6p7q.5 &2r""6r7s.) &;\'.# &;('),l('%$;).\u012b &2F""6F7G.\u011f &2J""6J7K.\u0113 &2L""6L7M.\u0107 &2X""6X7Y.\xfb &2P""6P7Q.\xef &2H""6H7I.\xe3 &2@""6@7A.\xd7 &2d""6d7e.\xcb &2R""6R7S.\xbf &2N""6N7O.\xb3 &2T""6T7U.\xa7 &2V""6V7W.\x9b &2f""6f7g.\x8f &2h""6h7i.\x83 &28""6879.w &2j""6j7k.k &;&.e &24""6475.Y &2l""6l7m.M &2n""6n7o.A &26""6677.5 &2p""6p7q.) &2r""6r7s/\u0134#0\u0131*;).\u012b &2F""6F7G.\u011f &2J""6J7K.\u0113 &2L""6L7M.\u0107 &2X""6X7Y.\xfb &2P""6P7Q.\xef &2H""6H7I.\xe3 &2@""6@7A.\xd7 &2d""6d7e.\xcb &2R""6R7S.\xbf &2N""6N7O.\xb3 &2T""6T7U.\xa7 &2V""6V7W.\x9b &2f""6f7g.\x8f &2h""6h7i.\x83 &28""6879.w &2j""6j7k.k &;&.e &24""6475.Y &2l""6l7m.M &2n""6n7o.A &26""6677.5 &2p""6p7q.) &2r""6r7s&&&#/"!&,)'),l("%;//?#2P\"\"6P7Q/0$;//'$8#:t# )(#'#(\"'#&'#"),l("%;//?#24\"\"6475/0$;//'$8#:u# )(#'#(\"'#&'#"),l("%;//?#2>\"\"6>7?/0$;//'$8#:v# )(#'#(\"'#&'#"),l("%;//?#2T\"\"6T7U/0$;//'$8#:w# )(#'#(\"'#&'#"),l("%;//?#2V\"\"6V7W/0$;//'$8#:x# )(#'#(\"'#&'#"),l('%2h""6h7i/0#;//\'$8":y" )("\'#&\'#'),l('%;//6#2f""6f7g/\'$8":z" )("\'#&\'#'),l("%;//?#2D\"\"6D7E/0$;//'$8#:{# )(#'#(\"'#&'#"),l("%;//?#22\"\"6273/0$;//'$8#:|# )(#'#(\"'#&'#"),l("%;//?#28\"\"6879/0$;//'$8#:}# )(#'#(\"'#&'#"),l("%;//0#;&/'$8\":~\" )(\"'#&'#"),l("%;&/0#;//'$8\":~\" )(\"'#&'#"),l("%;=/T#$;G.) &;K.# &;F0/*;G.) &;K.# &;F&/,$;>/#$+#)(#'#(\"'#&'#"),l('4\x7f""5!7\x80.A &4\x81""5!7\x82.5 &4\x83""5!7\x84.) &;3.# &;.'),l("%%;//Q#;&/H$$;J.# &;K0)*;J.# &;K&/,$;&/#$+$)($'#(#'#(\"'#&'#/\"!&,)"),l("%;//]#;&/T$%$;J.# &;K0)*;J.# &;K&/\"!&,)/1$;&/($8$:\x85$!!)($'#(#'#(\"'#&'#"),l(';..G &2L""6L7M.; &4\x86""5!7\x87./ &4\x83""5!7\x84.# &;3'),l('%2j""6j7k/J#4\x88""5!7\x89.5 &4\x8a""5!7\x8b.) &4\x8c""5!7\x8d/#$+")("\'#&\'#'),l("%;N/M#28\"\"6879/>$;O.\" &\"/0$;S/'$8$:\x8e$ )($'#(#'#(\"'#&'#"),l("%;N/d#28\"\"6879/U$;O.\" &\"/G$;S/>$;_/5$;l.\" &\"/'$8&:\x8f& )(&'#(%'#($'#(#'#(\"'#&'#"),l('%3\x90""5$7\x91.) &3\x92""5#7\x93/\' 8!:\x94!! )'),l('%;P/]#%28""6879/,#;R/#$+")("\'#&\'#." &"/6$2:""6:7;/\'$8#:\x95# )(#\'#("\'#&\'#'),l("$;+.) &;-.# &;Q/2#0/*;+.) &;-.# &;Q&&&#"),l('2<""6<7=.q &2>""6>7?.e &2@""6@7A.Y &2B""6B7C.M &2D""6D7E.A &22""6273.5 &26""6677.) &24""6475'),l('%$;+._ &;-.Y &2<""6<7=.M &2>""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E0e*;+._ &;-.Y &2<""6<7=.M &2>""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E&/& 8!:\x96! )'),l('%;T/J#%28""6879/,#;^/#$+")("\'#&\'#." &"/#$+")("\'#&\'#'),l("%;U.) &;\\.# &;X/& 8!:\x97! )"),l('%$%;V/2#2J""6J7K/#$+")("\'#&\'#0<*%;V/2#2J""6J7K/#$+")("\'#&\'#&/D#;W/;$2J""6J7K." &"/\'$8#:\x98# )(#\'#("\'#&\'#'),l('$4\x99""5!7\x9a/,#0)*4\x99""5!7\x9a&&&#'),l('%4$""5!7%/?#$4\x9b""5!7\x9c0)*4\x9b""5!7\x9c&/#$+")("\'#&\'#'),l('%2l""6l7m/?#;Y/6$2n""6n7o/\'$8#:\x9d# )(#\'#("\'#&\'#'),l('%%;Z/\xb3#28""6879/\xa4$;Z/\x9b$28""6879/\x8c$;Z/\x83$28""6879/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+-)(-\'#(,\'#(+\'#(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0790 &%2\x9e""6\x9e7\x9f/\xa4#;Z/\x9b$28""6879/\x8c$;Z/\x83$28""6879/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+,)(,\'#(+\'#(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u06f9 &%2\x9e""6\x9e7\x9f/\x8c#;Z/\x83$28""6879/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+*)(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u067a &%2\x9e""6\x9e7\x9f/t#;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+()((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0613 &%2\x9e""6\x9e7\x9f/\\#;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+&)(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u05c4 &%2\x9e""6\x9e7\x9f/D#;Z/;$28""6879/,$;[/#$+$)($\'#(#\'#("\'#&\'#.\u058d &%2\x9e""6\x9e7\x9f/,#;[/#$+")("\'#&\'#.\u056e &%2\x9e""6\x9e7\x9f/,#;Z/#$+")("\'#&\'#.\u054f &%;Z/\x9b#2\x9e""6\x9e7\x9f/\x8c$;Z/\x83$28""6879/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$++)(+\'#(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u04c7 &%;Z/\xaa#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x83$2\x9e""6\x9e7\x9f/t$;Z/k$28""6879/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+*)(*\'#()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0430 &%;Z/\xb9#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x92$%28""6879/,#;Z/#$+")("\'#&\'#." &"/k$2\x9e""6\x9e7\x9f/\\$;Z/S$28""6879/D$;Z/;$28""6879/,$;[/#$+))()\'#((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u038a &%;Z/\xc8#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xa1$%28""6879/,#;Z/#$+")("\'#&\'#." &"/z$%28""6879/,#;Z/#$+")("\'#&\'#." &"/S$2\x9e""6\x9e7\x9f/D$;Z/;$28""6879/,$;[/#$+()((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u02d5 &%;Z/\xd7#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xb0$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x89$%28""6879/,#;Z/#$+")("\'#&\'#." &"/b$%28""6879/,#;Z/#$+")("\'#&\'#." &"/;$2\x9e""6\x9e7\x9f/,$;[/#$+\')(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0211 &%;Z/\xfe#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xd7$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xb0$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x89$%28""6879/,#;Z/#$+")("\'#&\'#." &"/b$%28""6879/,#;Z/#$+")("\'#&\'#." &"/;$2\x9e""6\x9e7\x9f/,$;Z/#$+()((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#.\u0126 &%;Z/\u011c#%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xf5$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xce$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\xa7$%28""6879/,#;Z/#$+")("\'#&\'#." &"/\x80$%28""6879/,#;Z/#$+")("\'#&\'#." &"/Y$%28""6879/,#;Z/#$+")("\'#&\'#." &"/2$2\x9e""6\x9e7\x9f/#$+()((\'#(\'\'#(&\'#(%\'#($\'#(#\'#("\'#&\'#/& 8!:\xa0! )'),l('%;#/M#;#." &"/?$;#." &"/1$;#." &"/#$+$)($\'#(#\'#("\'#&\'#'),l("%;Z/;#28\"\"6879/,$;Z/#$+#)(#'#(\"'#&'#.# &;\\"),l("%;]/o#2J\"\"6J7K/`$;]/W$2J\"\"6J7K/H$;]/?$2J\"\"6J7K/0$;]/'$8':\xa1' )(''#(&'#(%'#($'#(#'#(\"'#&'#"),l('%2\xa2""6\xa27\xa3/2#4\xa4""5!7\xa5/#$+")("\'#&\'#.\x98 &%2\xa6""6\xa67\xa7/;#4\xa8""5!7\xa9/,$;!/#$+#)(#\'#("\'#&\'#.j &%2\xaa""6\xaa7\xab/5#;!/,$;!/#$+#)(#\'#("\'#&\'#.B &%4\xac""5!7\xad/,#;!/#$+")("\'#&\'#.# &;!'),l('%%;!." &"/[#;!." &"/M$;!." &"/?$;!." &"/1$;!." &"/#$+%)(%\'#($\'#(#\'#("\'#&\'#/\' 8!:\xae!! )'),l('$%22""6273/,#;`/#$+")("\'#&\'#0<*%22""6273/,#;`/#$+")("\'#&\'#&'),l(";a.A &;b.; &;c.5 &;d./ &;e.) &;f.# &;g"),l('%3\xaf""5*7\xb0/a#3\xb1""5#7\xb2.G &3\xb3""5#7\xb4.; &3\xb5""5$7\xb6./ &3\xb7""5#7\xb8.# &;6/($8":\xb9"! )("\'#&\'#'),l('%3\xba""5%7\xbb/I#3\xbc""5%7\xbd./ &3\xbe""5"7\xbf.# &;6/($8":\xc0"! )("\'#&\'#'),l('%3\xc1""5\'7\xc2/1#;\x8f/($8":\xc3"! )("\'#&\'#'),l('%3\xc4""5$7\xc5/1#;\xef/($8":\xc6"! )("\'#&\'#'),l('%3\xc7""5&7\xc8/1#;T/($8":\xc9"! )("\'#&\'#'),l('%3\xca""5"7\xcb/N#%2>""6>7?/,#;6/#$+")("\'#&\'#." &"/\'$8":\xcc" )("\'#&\'#'),l('%;h/P#%2>""6>7?/,#;i/#$+")("\'#&\'#." &"/)$8":\xcd""! )("\'#&\'#'),l('%$;j/�#*;j&&&#/"!&,)'),l('%$;j/�#*;j&&&#/"!&,)'),l(";k.) &;+.# &;-"),l('2l""6l7m.e &2n""6n7o.Y &24""6475.M &28""6879.A &2<""6<7=.5 &2@""6@7A.) &2B""6B7C'),l('%26""6677/n#;m/e$$%2<""6<7=/,#;m/#$+")("\'#&\'#0<*%2<""6<7=/,#;m/#$+")("\'#&\'#&/#$+#)(#\'#("\'#&\'#'),l('%;n/A#2>""6>7?/2$;o/)$8#:\xce#"" )(#\'#("\'#&\'#'),l("$;p.) &;+.# &;-/2#0/*;p.) &;+.# &;-&&&#"),l("$;p.) &;+.# &;-0/*;p.) &;+.# &;-&"),l('2l""6l7m.e &2n""6n7o.Y &24""6475.M &26""6677.A &28""6879.5 &2@""6@7A.) &2B""6B7C'),l(";\x90.# &;r"),l("%;\x8f/G#;'/>$;s/5$;'/,$;\x84/#$+%)(%'#($'#(#'#(\"'#&'#"),l(";M.# &;t"),l("%;\x7f/E#28\"\"6879/6$;u.# &;x/'$8#:\xcf# )(#'#(\"'#&'#"),l('%;v.# &;w/J#%26""6677/,#;\x83/#$+")("\'#&\'#." &"/#$+")("\'#&\'#'),l('%2\xd0""6\xd07\xd1/:#;\x80/1$;w." &"/#$+#)(#\'#("\'#&\'#'),l('%24""6475/,#;{/#$+")("\'#&\'#'),l("%;z/3#$;y0#*;y&/#$+\")(\"'#&'#"),l(";*.) &;+.# &;-"),l(';+.\x8f &;-.\x89 &22""6273.} &26""6677.q &28""6879.e &2:""6:7;.Y &2<""6<7=.M &2>""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E'),l('%;|/e#$%24""6475/,#;|/#$+")("\'#&\'#0<*%24""6475/,#;|/#$+")("\'#&\'#&/#$+")("\'#&\'#'),l('%$;~0#*;~&/e#$%22""6273/,#;}/#$+")("\'#&\'#0<*%22""6273/,#;}/#$+")("\'#&\'#&/#$+")("\'#&\'#'),l("$;~0#*;~&"),l(';+.w &;-.q &28""6879.e &2:""6:7;.Y &2<""6<7=.M &2>""6>7?.A &2@""6@7A.5 &2B""6B7C.) &2D""6D7E'),l('%%;"/\x87#$;".G &;!.A &2@""6@7A.5 &2F""6F7G.) &2J""6J7K0M*;".G &;!.A &2@""6@7A.5 &2F""6F7G.) &2J""6J7K&/#$+")("\'#&\'#/& 8!:\xd2! )'),l(";\x81.# &;\x82"),l('%%;O/2#2:""6:7;/#$+")("\'#&\'#." &"/,#;S/#$+")("\'#&\'#." &"'),l('$;+.\x83 &;-.} &2B""6B7C.q &2D""6D7E.e &22""6273.Y &28""6879.M &2:""6:7;.A &2<""6<7=.5 &2>""6>7?.) &2@""6@7A/\x8c#0\x89*;+.\x83 &;-.} &2B""6B7C.q &2D""6D7E.e &22""6273.Y &28""6879.M &2:""6:7;.A &2<""6<7=.5 &2>""6>7?.) &2@""6@7A&&&#'),l("$;y0#*;y&"),l('%3\x92""5#7\xd3/q#24""6475/b$$;!/�#*;!&&&#/L$2J""6J7K/=$$;!/�#*;!&&&#/\'$8%:\xd4% )(%\'#($\'#(#\'#("\'#&\'#'),l('2\xd5""6\xd57\xd6'),l('2\xd7""6\xd77\xd8'),l('2\xd9""6\xd97\xda'),l('2\xdb""6\xdb7\xdc'),l('2\xdd""6\xdd7\xde'),l('2\xdf""6\xdf7\xe0'),l('2\xe1""6\xe17\xe2'),l('2\xe3""6\xe37\xe4'),l('2\xe5""6\xe57\xe6'),l('2\xe7""6\xe77\xe8'),l("%;\x85.S &;\x86.M &;\x88.G &;\x89.A &;\x8a.; &;\x8b.5 &;\x8c./ &;\x8d.) &;\x8e.# &;6/& 8!:\xe9! )"),l("%;\x84/G#;'/>$;\x91/5$;'/,$;\x93/#$+%)(%'#($'#(#'#(\"'#&'#"),l("%;\x92/' 8!:\xea!! )"),l("%;!/5#;!/,$;!/#$+#)(#'#(\"'#&'#"),l("%$;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(0G*;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(&/& 8!:\xeb! )"),l("%;\xb5/Y#$%;A/,#;\xb5/#$+\")(\"'#&'#06*%;A/,#;\xb5/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),l('%;9/N#%2:""6:7;/,#;9/#$+")("\'#&\'#." &"/\'$8":\xec" )("\'#&\'#'),l("%;:.c &%;\x97/Y#$%;A/,#;\x97/#$+\")(\"'#&'#06*%;A/,#;\x97/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/& 8!:\xed! )"),l("%;L.# &;\x98/]#$%;B/,#;\x9a/#$+\")(\"'#&'#06*%;B/,#;\x9a/#$+\")(\"'#&'#&/'$8\":\xee\" )(\"'#&'#"),l("%;\x99.\" &\"/>#;@/5$;M/,$;?/#$+$)($'#(#'#(\"'#&'#"),l("%%;6/Y#$%;./,#;6/#$+\")(\"'#&'#06*%;./,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#.# &;H/' 8!:\xef!! )"),l(";\x9b.) &;\x9c.# &;\x9f"),l("%3\xf0\"\"5!7\xf1/:#;$;\xce/5$;./,$;\x8f/#$+%)(%'#($'#(#'#(\"'#&'#"),l("%$;!/�#*;!&&&#/' 8!:\u0149!! )"),l("%;\xd0/]#$%;A/,#;\xd0/#$+\")(\"'#&'#06*%;A/,#;\xd0/#$+\")(\"'#&'#&/'$8\":\u014a\" )(\"'#&'#"),l("%;\x98/]#$%;B/,#;\x9f/#$+\")(\"'#&'#06*%;B/,#;\x9f/#$+\")(\"'#&'#&/'$8\":\u014b\" )(\"'#&'#"),l('%;L.O &;\x98.I &%;@." &"/:#;t/1$;?." &"/#$+#)(#\'#("\'#&\'#/]#$%;B/,#;\x9f/#$+")("\'#&\'#06*%;B/,#;\x9f/#$+")("\'#&\'#&/\'$8":\u014c" )("\'#&\'#'),l("%;\xd3/]#$%;B/,#;\xd4/#$+\")(\"'#&'#06*%;B/,#;\xd4/#$+\")(\"'#&'#&/'$8\":\u014d\" )(\"'#&'#"),l("%;\x95/& 8!:\u014e! )"),l('%3\u014f""5(7\u0150/:#;$;6/5$;;/,$;\xeb/#$+%)(%'#($'#(#'#(\"'#&'#"),l('%3\x92""5#7\xd3.# &;6/\' 8!:\u0189!! )'),l('%3\xb1""5#7\u018a.G &3\xb3""5#7\u018b.; &3\xb7""5#7\u018c./ &3\xb5""5$7\u018d.# &;6/\' 8!:\u018e!! )'),l('%;\xed/D#%;C/,#;\xee/#$+")("\'#&\'#." &"/#$+")("\'#&\'#'),l("%;U.) &;\\.# &;X/& 8!:\u018f! )"),l('%%;!." &"/[#;!." &"/M$;!." &"/?$;!." &"/1$;!." &"/#$+%)(%\'#($\'#(#\'#("\'#&\'#/\' 8!:\u0190!! )'),l('%%;!/?#;!." &"/1$;!." &"/#$+#)(#\'#("\'#&\'#/\' 8!:\u0191!! )'),l(";\xbd"),l('%;\x9d/^#$%;B/,#;\xf2/#$+")("\'#&\'#06*%;B/,#;\xf2/#$+")("\'#&\'#&/($8":\u0192"!!)("\'#&\'#'),l(";\xf3.# &;\x9f"),l('%2\u0193""6\u01937\u0194/L#;""6>7?'),l('%;\xff/b#28""6879/S$;\xfa/J$%2\u01a1""6\u01a17\u01a2/,#;\xeb/#$+")("\'#&\'#." &"/#$+$)($\'#(#\'#("\'#&\'#'),l('%3\u01a3""5%7\u01a4.) &3\u01a5""5$7\u01a6/\' 8!:\u019f!! )'),l('%;\xeb/O#3\xb1""5#7\xb2.6 &3\xb3""5#7\xb4.* &$;+0#*;+&/\'$8":\u01a7" )("\'#&\'#'),l("%;\u0103/\x87#2F\"\"6F7G/x$;\u0102/o$2F\"\"6F7G/`$;\u0102/W$2F\"\"6F7G/H$;\u0102/?$2F\"\"6F7G/0$;\u0104/'$8):\u01a8) )()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#"),l("%;#/>#;#/5$;#/,$;#/#$+$)($'#(#'#(\"'#&'#"),l("%;\u0102/,#;\u0102/#$+\")(\"'#&'#"),l("%;\u0102/5#;\u0102/,$;\u0102/#$+#)(#'#(\"'#&'#"),l("%;\x84/U#;'/L$;\x91/C$;'/:$;\x8f/1$; .\" &\"/#$+&)(&'#(%'#($'#(#'#(\"'#&'#"),l('%2\u01a9""6\u01a97\u01aa.) &2\u01ab""6\u01ab7\u01ac/w#;0/n$;\u0107/e$$%;B/2#;\u0108.# &;\x9f/#$+")("\'#&\'#0<*%;B/2#;\u0108.# &;\x9f/#$+")("\'#&\'#&/#$+$)($\'#(#\'#("\'#&\'#'),l(";\x98.# &;L"),l("%2\u01ad\"\"6\u01ad7\u01ae/5#;-1&&r.indexOf("chrome")<0&&(n=!0);var o={};return n&&(o.modifiers=[e.WebRTC.Modifiers.stripG722]),this.options.ua.uri||(this.anonymous=!0),this.ua=new e.UA({wsServers:this.options.ua.wsServers,uri:this.options.ua.uri,authorizationUser:this.options.ua.authorizationUser,password:this.options.ua.password,displayName:this.options.ua.displayName,traceSip:this.options.ua.traceSip,userAgentString:this.options.ua.userAgentString,register:!0,sessionDescriptionHandlerFactoryOptions:o}),this.state=i.STATUS_NULL,this.logger=this.ua.getLogger("sip.simple"),this.ua.on("registered",function(){this.emit("registered",this.ua)}.bind(this)),this.ua.on("unregistered",function(){this.emit("unregistered",this.ua)}.bind(this)),this.ua.on("failed",function(){this.emit("unregistered",this.ua)}.bind(this)),this.ua.on("invite",function(e){if(this.state!==i.STATUS_NULL&&this.state!==i.STATUS_COMPLETED)return this.logger.warn("Rejecting incoming call. Simple only supports 1 call at a time"),void e.reject();this.session=e,this.setupSession(),this.emit("ringing",this.session)}.bind(this)),this.ua.on("message",function(e){this.emit("message",e)}.bind(this)),this};return s.prototype=Object.create(e.EventEmitter.prototype),s.C=i,s.prototype.call=function(e){if(this.ua&&this.checkRegistration()){if(this.state===i.STATUS_NULL||this.state===i.STATUS_COMPLETED)return this.options.media.remote.audio&&(this.options.media.remote.audio.autoplay=!0),this.options.media.remote.video&&(this.options.media.remote.video.autoplay=!0),this.options.media.local&&this.options.media.local.video&&(this.options.media.local.video.autoplay=!0,this.options.media.local.video.volume=0),this.session=this.ua.invite(e,{sessionDescriptionHandlerOptions:{constraints:{audio:this.audio,video:this.video}}}),this.setupSession(),this.session;this.logger.warn("Cannot make more than a single call with Simple")}else this.logger.warn("A registered UA is required for calling")},s.prototype.answer=function(){if(this.state===i.STATUS_NEW||this.state===i.STATUS_CONNECTING)return this.options.media.remote.audio&&(this.options.media.remote.audio.autoplay=!0),this.options.media.remote.video&&(this.options.media.remote.video.autoplay=!0),this.session.accept({sessionDescriptionHandlerOptions:{constraints:{audio:this.audio,video:this.video}}});this.logger.warn("No call to answer")},s.prototype.reject=function(){if(this.state===i.STATUS_NEW||this.state===i.STATUS_CONNECTING)return this.session.reject();this.logger.warn("Call is already answered")},s.prototype.hangup=function(){if(this.state===i.STATUS_CONNECTED||this.state===i.STATUS_CONNECTING||this.state===i.STATUS_NEW)return this.state!==i.STATUS_CONNECTED?this.session.cancel():this.session.bye();this.logger.warn("No active call to hang up on")},s.prototype.hold=function(){if(this.state===i.STATUS_CONNECTED&&!this.session.local_hold)return this.mute(),this.logger.log("Placing session on hold"),this.session.hold();this.logger.warn("Cannot put call on hold")},s.prototype.unhold=function(){if(this.state===i.STATUS_CONNECTED&&this.session.local_hold)return this.unmute(),this.logger.log("Placing call off hold"),this.session.unhold();this.logger.warn("Cannot unhold a call that is not on hold")},s.prototype.mute=function(){this.state===i.STATUS_CONNECTED?(this.logger.log("Muting Audio"),this.toggleMute(!0)):this.logger.warn("An acitve call is required to mute audio")},s.prototype.unmute=function(){this.state===i.STATUS_CONNECTED?(this.logger.log("Unmuting Audio"),this.toggleMute(!1)):this.logger.warn("An active call is required to unmute audio")},s.prototype.sendDTMF=function(e){this.state===i.STATUS_CONNECTED?(this.logger.log("Sending DTMF tone: "+e),this.session.dtmf(e)):this.logger.warn("An active call is required to send a DTMF tone")},s.prototype.message=function(e,t){this.ua&&this.checkRegistration()?e&&t?this.ua.message(e,t):this.logger.warn("A destination and message are required to send a message"):this.logger.warn("A registered UA is required to send a message")},s.prototype.checkRegistration=function(){return this.anonymous||this.ua&&this.ua.isRegistered()},s.prototype.setupRemoteMedia=function(){var e,i=this.session.sessionDescriptionHandler.peerConnection;i.getReceivers?(e=new t.window.MediaStream,i.getReceivers().forEach(function(t){var i=t.track;i&&e.addTrack(i)})):e=i.getRemoteStreams()[0],this.video?(this.options.media.remote.video.srcObject=e,this.options.media.remote.video.play().catch(function(){this.logger.log("play was rejected")}.bind(this))):this.audio&&(this.options.media.remote.audio.srcObject=e,this.options.media.remote.audio.play().catch(function(){this.logger.log("play was rejected")}.bind(this)))},s.prototype.setupLocalMedia=function(){if(this.video&&this.options.media.local&&this.options.media.local.video){var e,i=this.session.sessionDescriptionHandler.peerConnection;i.getSenders?(e=new t.window.MediaStream,i.getSenders().forEach(function(t){var i=t.track;i&&"video"===i.kind&&e.addTrack(i)})):e=i.getLocalStreams()[0],this.options.media.local.video.srcObject=e,this.options.media.local.video.volume=0,this.options.media.local.video.play()}},s.prototype.cleanupMedia=function(){this.video&&(this.options.media.remote.video.srcObject=null,this.options.media.remote.video.pause(),this.options.media.local&&this.options.media.local.video&&(this.options.media.local.video.srcObject=null,this.options.media.local.video.pause())),this.audio&&(this.options.media.remote.audio.srcObject=null,this.options.media.remote.audio.pause())},s.prototype.setupSession=function(){this.state=i.STATUS_NEW,this.emit("new",this.session),this.session.on("progress",this.onProgress.bind(this)),this.session.on("accepted",this.onAccepted.bind(this)),this.session.on("rejected",this.onEnded.bind(this)),this.session.on("failed",this.onFailed.bind(this)),this.session.on("terminated",this.onEnded.bind(this))},s.prototype.destroyMedia=function(){this.session.sessionDescriptionHandler.close()},s.prototype.toggleMute=function(e){var t=this.session.sessionDescriptionHandler.peerConnection;t.getSenders?t.getSenders().forEach(function(t){t.track&&(t.track.enabled=!e)}):t.getLocalStreams().forEach(function(t){t.getAudioTracks().forEach(function(t){t.enabled=!e}),t.getVideoTracks().forEach(function(t){t.enabled=!e})})},s.prototype.onAccepted=function(){this.state=i.STATUS_CONNECTED,this.emit("connected",this.session),this.setupLocalMedia(),this.setupRemoteMedia(),this.session.sessionDescriptionHandler.on("addTrack",function(){this.logger.log("A track has been added, triggering new remoteMedia setup"),this.setupRemoteMedia()}.bind(this)),this.session.sessionDescriptionHandler.on("addStream",function(){this.logger.log("A stream has been added, trigger new remoteMedia setup"),this.setupRemoteMedia()}.bind(this)),this.session.on("hold",function(){this.emit("hold",this.session)}.bind(this)),this.session.on("unhold",function(){this.emit("unhold",this.session)}.bind(this)),this.session.on("dtmf",function(e){this.emit("dtmf",e)}.bind(this)),this.session.on("bye",this.onEnded.bind(this))},s.prototype.onProgress=function(){this.state=i.STATUS_CONNECTING,this.emit("connecting",this.session)},s.prototype.onFailed=function(){this.onEnded()},s.prototype.onEnded=function(){this.state=i.STATUS_COMPLETED,this.emit("ended",this.session),this.cleanupMedia()},s}}).call(t,i(0))},function(e,t,i){"use strict";(function(t){function s(e,t){if(null!=e){var i=t.charAt(0).toUpperCase()+t.slice(1),s=[t,"webkit"+i,"moz"+i];for(var r in s){var n=e[s[r]];if(n)return n.bind(e)}}}var r=t.window||t;e.exports={WebSocket:r.WebSocket,Transport:i(35),open:r.open,Promise:r.Promise,timers:r,console:r.console||{debug:function(){},log:function(){},warn:function(){},error:function(){}},addEventListener:s(r,"addEventListener"),removeEventListener:s(r,"removeEventListener")}}).call(t,i(0))},function(e,t,i){"use strict";e.exports=function(e,t){var i;return i=function(e,t){this.logger=e.getLogger("sip.transport"),this.ua=e,this.ws=null,this.server=t,this.reconnection_attempts=0,this.closed=!1,this.connected=!1,this.reconnectTimer=null,this.lastTransportError={},this.keepAliveInterval=e.configuration.keepAliveInterval,this.keepAliveTimeout=null,this.keepAliveTimer=null,this.ua.transport=this,this.connect()},i.prototype={send:function(e){var i=e.toString();return this.ws&&this.ws.readyState===t.OPEN?(!0===this.ua.configuration.traceSip&&this.logger.log("sending WebSocket message:\n\n"+i+"\n"),this.ws.send(i),!0):(this.logger.warn("unable to send message, WebSocket is not open"),!1)},sendKeepAlive:function(){if(!this.keepAliveTimeout)return this.keepAliveTimeout=e.Timers.setTimeout(function(){this.ua.emit("keepAliveTimeout")}.bind(this),1e4),this.send("\r\n\r\n")},startSendingKeepAlives:function(){this.keepAliveInterval&&!this.keepAliveTimer&&(this.keepAliveTimer=e.Timers.setTimeout(function(){this.sendKeepAlive(),this.keepAliveTimer=null,this.startSendingKeepAlives()}.bind(this),function(e){var t=.8*e;return 1e3*(Math.random()*(e-t)+t)}(this.keepAliveInterval)))},stopSendingKeepAlives:function(){e.Timers.clearTimeout(this.keepAliveTimer),e.Timers.clearTimeout(this.keepAliveTimeout),this.keepAliveTimer=null,this.keepAliveTimeout=null},disconnect:function(){this.ws&&(e.Timers.clearTimeout(this.reconnectTimer),this.stopSendingKeepAlives(),this.closed=!0,this.logger.log("closing WebSocket "+this.server.ws_uri),this.ws.close(),this.ws=null),null!==this.reconnectTimer&&(e.Timers.clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.ua.emit("disconnected",{transport:this,code:this.lastTransportError.code,reason:this.lastTransportError.reason}))},connect:function(){var e=this;if(this.ws&&(this.ws.readyState===t.OPEN||this.ws.readyState===t.CONNECTING))return this.logger.log("WebSocket "+this.server.ws_uri+" is already connected"),!1;this.ws&&(this.ws.close(),this.ws=null),this.logger.log("connecting to WebSocket "+this.server.ws_uri),this.ua.onTransportConnecting(this,0===this.reconnection_attempts?1:this.reconnection_attempts);try{this.ws=new t(this.server.ws_uri,"sip")}catch(e){this.logger.warn("error connecting to WebSocket "+this.server.ws_uri+": "+e)}this.ws.binaryType="arraybuffer",this.ws.onopen=function(){e.onOpen()},this.ws.onclose=function(t){e.onClose(t),this.onopen=null,this.onclose=null,this.onmessage=null,this.onerror=null},this.ws.onmessage=function(t){e.onMessage(t)},this.ws.onerror=function(t){e.onError(t)}},onOpen:function(){this.connected=!0,this.logger.log("WebSocket "+this.server.ws_uri+" connected"),null!==this.reconnectTimer&&(e.Timers.clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.reconnection_attempts=0,this.closed=!1,this.ua.onTransportConnected(this),this.startSendingKeepAlives()},onClose:function(e){var t=this.connected;this.lastTransportError.code=e.code,this.lastTransportError.reason=e.reason,this.stopSendingKeepAlives(),this.reconnection_attempts>0?(this.logger.log("Reconnection attempt "+this.reconnection_attempts+" failed (code: "+e.code+(e.reason?"| reason: "+e.reason:"")+")"),this.reconnect()):(this.connected=!1,this.logger.log("WebSocket disconnected (code: "+e.code+(e.reason?"| reason: "+e.reason:"")+")"),!1===e.wasClean&&this.logger.warn("WebSocket abrupt disconnection"),!0===t?(this.ua.onTransportClosed(this),this.closed?this.ua.emit("disconnected",{transport:this,code:this.lastTransportError.code,reason:this.lastTransportError.reason}):this.reconnect()):this.ua.onTransportError(this))},onMessage:function(t){var i,s,r=t.data;if("\r\n"===r)return e.Timers.clearTimeout(this.keepAliveTimeout),this.keepAliveTimeout=null,void(!0===this.ua.configuration.traceSip&&this.logger.log("received WebSocket message with CRLF Keep Alive response"));if("string"!=typeof r){try{r=String.fromCharCode.apply(null,new Uint8Array(r))}catch(e){return void this.logger.warn("received WebSocket binary message failed to be converted into string, message discarded")}!0===this.ua.configuration.traceSip&&this.logger.log("received WebSocket binary message:\n\n"+r+"\n")}else!0===this.ua.configuration.traceSip&&this.logger.log("received WebSocket text message:\n\n"+r+"\n");if((i=e.Parser.parseMessage(r,this.ua))&&!(this.ua.status===e.UA.C.STATUS_USER_CLOSED&&i instanceof e.IncomingRequest)&&e.sanityCheck(i,this.ua,this))if(i instanceof e.IncomingRequest)i.transport=this,this.ua.receiveRequest(i);else if(i instanceof e.IncomingResponse)switch(i.method){case e.C.INVITE:(s=this.ua.transactions.ict[i.via_branch])&&s.receiveResponse(i);break;case e.C.ACK:break;default:(s=this.ua.transactions.nict[i.via_branch])&&s.receiveResponse(i)}},onError:function(e){this.logger.warn("WebSocket connection error: "),this.logger.warn(e)},reconnect:function(){var t=this;this.reconnection_attempts+=1,this.reconnection_attempts>this.ua.configuration.wsServerMaxReconnection?(this.logger.warn("maximum reconnection attempts for WebSocket "+this.server.ws_uri),this.ua.onTransportError(this)):1===this.reconnection_attempts?(this.logger.log("Connection to WebSocket "+this.server.ws_uri+" severed, attempting first reconnect"),t.connect()):(this.logger.log("trying to reconnect to WebSocket "+this.server.ws_uri+" (reconnection attempt "+this.reconnection_attempts+")"),this.reconnectTimer=e.Timers.setTimeout(function(){t.connect(),t.reconnectTimer=null},1e3*this.ua.configuration.wsServerReconnectionTimeout))}},i.C={STATUS_READY:0,STATUS_DISCONNECTED:1,STATUS_ERROR:2},i}}])}); \ No newline at end of file