text: ﻿/*
  * Copyright (C) 2012-2015 Doubango Telecom <http://www.doubango.org>
  * License: BSD
  * This file is part of Open Source sipML5 solution <http://www.sipml5.org>
  */
  tsip_response.prototype = Object.create(tsip_message.prototype);
  tsip_request.prototype = Object.create(tsip_message.prototype);
  
  tsip_message.prototype.__s_version_10 = "SIP/1.0";
  tsip_message.prototype.__s_version_20 = "SIP/2.0";
  tsip_message.prototype.__s_version_default = tsip_message.prototype.__s_version_20;
  
  var tsip_message_type_e =
  {
      UNKNOWN: 0, 
      REQUEST: 1,
      RESPONSE: 2
  };
  
  var tsip_request_type_e =
  {
      NONE: { i_id: -1, s_name: "NONE" },
  
      ACK: { i_id: 0, s_name: "ACK" },
      BYE: { i_id: 1, s_name: "BYE" },
      CANCEL: { i_id: 2, s_name: "CANCEL" },
      INVITE: { i_id: 3, s_name: "INVITE" },
      OPTIONS: { i_id: 4, s_name: "OPTIONS" },
      REGISTER: { i_id: 5, s_name: "REGISTER" },
      SUBSCRIBE: { i_id: 6, s_name: "SUBSCRIBE" },
      NOTIFY: { i_id: 7, s_name: "NOTIFY" },
      REFER: { i_id: 8, s_name: "REFER" },
      INFO: { i_id: 9, s_name: "INFO" },
      UPDATE: { i_id: 10, s_name: "UPDATE" },
      MESSAGE: { i_id: 11, s_name: "MESSAGE" },
      PUBLISH: { i_id: 12, s_name: "PUBLISH" },
      PRACK: { i_id: 13, s_name: "PRACK" }
  };
  
  
  function tsip_message(e_type) {
      this.s_version = tsip_message.prototype.__s_version_default; // The SIP version. Only 'SIP/2.0' is supported
      this.e_type = e_type;
  
      // Request-Line / Response-Line
      this.line = {
          request: {}, // s_method, o_uri
          response: {} // i_status_code, s_reason_phrase
      };
  
      // Most common headers
      this.o_hdr_firstVia = null;
      this.o_hdr_From = null;
      this.o_hdr_To = null;
      this.o_hdr_Contact = null;
      this.o_hdr_Call_ID = null;
      this.o_hdr_CSeq = null;
      this.o_hdr_Expires = null;
  
      this.o_hdr_Content_Type = null;
      this.o_hdr_Content_Length = null;
  
      this.o_content = null;
  
      // Other headers
      this.ao_headers = new Array();
  
      // To hack the message
      this.s_sigcomp_id = null;
      this.o_socket = null;
      this.o_remote_addr = null;
      this.b_update = false;
  }
  
  function tsip_response(i_status_code, s_reason_phrase, o_request) {
      if(!s_reason_phrase || !o_request){
          tsk_utils_log_error("Invalid argument");
          return null;
      }
      tsip_message.call(this, tsip_message_type_e.RESPONSE);
  	this.line.response.i_status_code = i_status_code;
  	this.line.response.s_reason_phrase = s_reason_phrase; 
  				
  	/* Copy network information */
  	this.o_socket = o_request.o_socket;
  	this.o_remote_addr = o_request.o_remote_addr;
  
  	/*
  	RFC 3261 - 8.2.6.2 Headers and Tags
  
  	The From field of the response MUST equal the From header field of
  	the request.  The Call-ID header field of the response MUST equal the
  	Call-ID header field of the request.  The CSeq header field of the
  	response MUST equal the CSeq field of the request.  The Via header
  	field values in the response MUST equal the Via header field values
  	in the request and MUST maintain the same ordering.
  
  	If a request contained a To tag in the request, the To header field
  	in the response MUST equal that of the request.  However, if the To
  	header field in the request did not contain a tag, the URI in the To
  	header field in the response MUST equal the URI in the To header
  	field; additionally, the UAS MUST add a tag to the To header field in
  	the response (with the exception of the 100 (Trying) response, in
  	which a tag MAY be present).  This serves to identify the UAS that is
  	responding, possibly resulting in a component of a dialog ID.  The
  	same tag MUST be used for all responses to that request, both final
  	and provisional (again excepting the 100 (Trying)).  Procedures for
  	the generation of tags are defined in Section 19.3.
  	*/
  	this.o_hdr_From = o_request.o_hdr_From;
  	this.o_hdr_Call_ID = o_request.o_hdr_Call_ID;
  	this.o_hdr_CSeq = o_request.o_hdr_CSeq;
  	this.o_hdr_firstVia = o_request.o_hdr_firstVia;
  	/* All other VIAs */
  	if(this.o_hdr_firstVia){
  		var i_index = 1;
  		var o_hdr_via;
  		while ((o_hdr_via = o_request.get_header_at(tsip_header_type_e.Via, i_index++))) {
  			this.add_header(o_hdr_via);
  		}
  	}
  	/* Record routes */
  	{
  		var i_index = 0;
  		var o_hdr_record_route;
  		while((o_hdr_record_route = o_request.get_header_at(tsip_header_type_e.Record_Route, i_index++))){
  			this.add_header(o_hdr_record_route);
  		}
  	}
  	this.o_hdr_To = o_request.o_hdr_To;
  	this.add_header(new tsip_header_Content_Length(0));
  }
  
  function tsip_request(s_method, o_uri_request, o_uri_from, o_uri_to, s_call_id, i_cseq){
      if(!s_method || !o_uri_request || !s_call_id){
          tsk_utils_log_error("Invalid argument");
          return null;
      }
  
      tsip_message.call(this, tsip_message_type_e.REQUEST);
      this.line.request.s_method = s_method;
      this.line.request.o_uri = o_uri_request;
      this.line.request.e_type = tsip_message.prototype.GetRequestType(s_method);
  
  	/* RFC 3261 8.1.1 Generating the Request
  		A valid SIP request formulated by a UAC MUST, at a minimum, contain
  		the following header fields: To, From, CSeq, Call-ID, Max-Forwards,
  		and Via; all of these header fields are mandatory in all SIP
  		requests.  These six header fields are the fundamental building
  		blocks of a SIP message, as they jointly provide for most of the
  		critical message routing services including the addressing of
  		messages, the routing of responses, limiting message propagation,
  		ordering of messages, and the unique identification of transactions.
  		These header fields are in addition to the mandatory request line,
  		which contains the method, Request-URI, and SIP version.
  	*/
      this.add_headers( 
          new tsip_header_CSeq(i_cseq, s_method),
          new tsip_header_Call_ID(s_call_id),
          new tsip_header_Max_Forwards(TSIP_HEADER_MAX_FORWARDS_DEFAULT),
          /* Via will be added by the transport layer */
  		new tsip_header_Content_Length(0));
      if (o_uri_to) {
          this.add_headers(new tsip_header_To(o_uri_to, null));
      }
      if (o_uri_from) {
          this.add_headers(new tsip_header_From(o_uri_from, null));
      }
  }
  
  // b_top: optional
  tsip_message.prototype.add_header = function (o_hdr, b_top) {
      if (!o_hdr) {
          tsk_utils_log_error("Invalid argument");
          return -1;
      }
  
      switch (o_hdr.e_type) {
          case tsip_header_type_e.Via:
              {
                  if (!this.o_hdr_firstVia) {
                      this.o_hdr_firstVia = o_hdr;
                      return 0;
                  }
                  break;
              }
          case tsip_header_type_e.From:
              {
                  if (!this.o_hdr_From) {
                      this.o_hdr_From = o_hdr;
                      return 0;
                  }
                  break;
              }
          case tsip_header_type_e.To:
              {
                  if (!this.o_hdr_To) {
                      this.o_hdr_To = o_hdr;
                      return 0;
                  }
                  break;
              }
          case tsip_header_type_e.Contact:
              {
                  if (!this.o_hdr_Contact) {
                      this.o_hdr_Contact = o_hdr;
                      return 0;
                  }
                  break;
              }
          case tsip_header_type_e.Call_ID:
              {
                  if (!this.o_hdr_Call_ID) {
                      this.o_hdr_Call_ID = o_hdr;
                      return 0;
                  }
                  break;
              }
          case tsip_header_type_e.CSeq:
              {
                  if (!this.o_hdr_CSeq) {
                      this.o_hdr_CSeq = o_hdr;
                      return 0;
                  }
                  break;
              }
          case tsip_header_type_e.Expires:
              {
                  if (!this.o_hdr_Expires) {
                      this.o_hdr_Expires = o_hdr;
                      return 0;
                  }
                  break;
              }
          case tsip_header_type_e.Content_Type:
              {
                  if (!this.o_hdr_Content_Type) {
                      this.o_hdr_Content_Type = o_hdr;
                      return 0;
                  }
                  break;
              }
          case tsip_header_type_e.Content_Length:
              {
                  if (!this.o_hdr_Content_Length) {
                      this.o_hdr_Content_Length = o_hdr;
                      return 0;
                  }
                  break;
              }
      }
  
      if (b_top) {
          this.ao_headers.unshift(o_hdr);
      }
      else {
          this.ao_headers.push(o_hdr);
      }
  
      return 0;
  }
  
  // add_headers(...);
  tsip_message.prototype.add_headers = function() {
      for (var i = 0; i < arguments.length; ++i) {
          if (arguments[i]) {
              this.add_header(arguments[i]);
          }
      }
      return 0;
  }
  
  tsip_message.prototype.get_header_at = function (e_hdr_type, i_index) {
      var i_pos = 0;
  
      switch (e_hdr_type) {
          case tsip_header_type_e.Via:
              {
                  if (i_index == 0) {
                      return this.o_hdr_firstVia;
                  }
                  ++i_pos;
                  break;
              }
          case tsip_header_type_e.From:
              {
                  if (i_index == 0) {
                      return this.o_hdr_From;
                  }
                  ++i_pos;
                  break;
              }
          case tsip_header_type_e.To:
              {
                  if (i_index == 0) {
                      return this.o_hdr_To;
                  }
                  ++i_pos;
                  break;
              }
          case tsip_header_type_e.Contact:
              {
                  if (i_index == 0) {
                      return this.o_hdr_Contact;
                  }
                  ++i_pos;
                  break;
              }
          case tsip_header_type_e.Call_ID:
              {
                  if (i_index == 0) {
                      return this.o_hdr_Call_ID;
                  }
                  ++i_pos;
                  break;
              }
          case tsip_header_type_e.CSeq:
              {
                  if (i_index == 0) {
                      return this.o_hdr_CSeq;
                  }
                  ++i_pos;
                  break;
              }
          case tsip_header_type_e.Expires:
              {
                  if (i_index == 0) {
                      return this.o_hdr_Expires;
                  }
                  ++i_pos;
                  break;
              }
          case tsip_header_type_e.Content_Type:
              {
                  if (i_index == 0) {
                      return this.o_hdr_Content_Type;
                  }
                  ++i_pos;
                  break;
              }
          case tsip_header_type_e.Content_Length:
              {
                  if (i_index == 0) {
                      return this.o_hdr_Content_Length;
                  }
                  ++i_pos;
                  break;
              }
      }
  
      for (var i = 0; i < this.ao_headers.length; ++i) {
          if (this.ao_headers[i].e_type == e_hdr_type) {
              if (i_pos++ >= i_index) {
                  return this.ao_headers[i];
              }
          }
      }
  
      return null;
  }
  
  tsip_message.prototype.get_header = function (e_hdr_type) {
      return this.get_header_at(e_hdr_type, 0);
  }
  
  tsip_message.prototype.get_response_code = function(){
      return this.is_response() ? this.line.response.i_status_code : 0;
  }
  
  tsip_message.prototype.get_response_phrase = function () {
      return this.is_response() ? this.line.response.s_reason_phrase : null;
  }
  
  tsip_message.prototype.is_allowed = function (s_method) {
      if (!s_method) {
          tsk_utils_log_error("Invalid argument");
          return false;
      }
  
      var o_hdr_allow;
      var i_index = 0;
  
      while ((o_hdr_allow = this.get_header_at(tsip_header_type_e.Allow, i_index++))) {
          if (o_hdr_allow.has_value(s_method)) {
              return true;
          }
      }
      return false;
  }
  
  tsip_message.prototype.is_supported = function (s_option) {
      if (!s_option) {
          tsk_utils_log_error("Invalid argument");
          return false;
      }
  
      var o_hdr_supported;
      var i_index = 0;
  
      while ((o_hdr_supported = this.get_header_at(tsip_header_type_e.Supported, i_index++))) {
          if (o_hdr_supported.has_value(s_option)) {
              return true;
          }
      }
      return false;
  }
  
  tsip_message.prototype.is_required = function (s_option) {
      if (!s_option) {
          tsk_utils_log_error("Invalid argument");
          return false;
      }
  
      var o_hdr_require;
      var i_index = 0;
  
      while ((o_hdr_require = this.get_header_at(tsip_header_type_e.Require, i_index++))) {
          if (o_hdr_require.has_value(s_option)) {
              return true;
          }
      }
      return false;
  }
  
  tsip_message.prototype.get_expires = function () {
      if (this.o_hdr_Expires) {
          return this.o_hdr_Expires.i_value;
      }
      if (this.o_hdr_Contact) {
          return this.o_hdr_Contact.i_expires;
      }
      return -1;
  }
  
  tsip_message.prototype.has_content = function () {
      return this.get_content_length() > 0 && this.o_content;
  }
  
  tsip_message.prototype.get_content_length = function () {
      return this.o_hdr_Content_Length ? this.o_hdr_Content_Length.i_value : 0;
  }
  
  tsip_message.prototype.get_content_type = function () {
      return (this.o_hdr_Content_Type) ? this.o_hdr_Content_Type.s_type : null;
  }
  
  tsip_message.prototype.get_content = function () {
      return this.o_content;
  }
  
  tsip_message.prototype.get_content_as_string = function () {
      if (this.o_content) {
          /*if (this.o_content instanceof String) {
              this.o_content;
          }
          else */if (this.o_content instanceof Array) {
              return tsk_buff_u8b2utf8(this.o_content);
          }
      }
      return this.o_content ? this.o_content.toString() : null;
  }
  
  // s_content_type is optional
  // i_length is optional
  tsip_message.prototype.add_content = function (o_content, s_content_type, i_length) {
      if (s_content_type) {
          this.o_hdr_Content_Type = new tsip_header_Content_Type(s_content_type);
      }
  
      if (o_content && typeof i_length == "undefined") {
          if (o_content instanceof String || typeof o_content == "string") {
              i_length = unescape(encodeURIComponent(o_content)).length;
          }
          else if (o_content.byteLength) {
              i_length = o_content.byteLength;
          }
          else if (o_content.length) {
              i_length = o_content.length;
          }
          else {
              tsk_utils_log_error("cannot stat content-length");
              i_length = 0;
          }
      }
  
  
      this.o_hdr_Content_Length = new tsip_header_Content_Length(i_length);
      this.o_content = o_content;
  }
  
  tsip_message.prototype.toString = function () {
      var s_str = null;
  
      if (this.e_type == tsip_message_type_e.REQUEST) {
          s_str = tsk_string_format("{0} {1} {2}\r\n",
                      this.line.request.s_method, tsip_uri_tostring(this.line.request.o_uri, true, false), this.s_version);
      }
      else {
          s_str = tsk_string_format("{0} {1} {2}\r\n", this.s_version, this.line.response.i_status_code, this.line.response.s_reason_phrase);
      }
  
      /* First Via */
      if (this.o_hdr_firstVia) {
          s_str += this.o_hdr_firstVia.tostring_full();
      }
      /* From */
      if (this.o_hdr_From) {
          s_str += this.o_hdr_From.tostring_full();
      }
      /* To */
      if (this.o_hdr_To) {
          s_str += this.o_hdr_To.tostring_full();
      }
      /* Contact */
      if (this.o_hdr_Contact) {
          s_str += this.o_hdr_Contact.tostring_full();
      }
      /* Call_id */
      if (this.o_hdr_Call_ID) {
          s_str += this.o_hdr_Call_ID.tostring_full();
      }
      /* CSeq */
      if (this.o_hdr_CSeq) {
          s_str += this.o_hdr_CSeq.tostring_full();
      }
      /* Expires */
      if (this.o_hdr_Expires) {
          s_str += this.o_hdr_Expires.tostring_full();
      }
      /* Content-Type */
      if (this.o_hdr_Content_Type) {
          s_str += this.o_hdr_Content_Type.tostring_full();
      }
      /* Content-Length*/
      if (this.o_hdr_Content_Length) {
          s_str += this.o_hdr_Content_Length.tostring_full();
      }
  
      /* All other headers */
      for (var i = 0; i < this.ao_headers.length; ++i) {
          s_str += this.ao_headers[i].tostring_full();
      }
  
      /* EMPTY LINE */
      s_str += "\r\n";
  
      /* CONTENT */
      if (this.has_content()) {
          s_str += this.get_content_as_string();
      }
  
      return s_str;
  }
  
  tsip_message.prototype.is_request = function () {
      return this.e_type == tsip_message_type_e.REQUEST;
  }
  
  tsip_message.prototype.is_response = function () {
      return this.e_type == tsip_message_type_e.RESPONSE;
  }
  
  tsip_message.prototype.is_req_type = function (e_type) {
      return this.is_request() && this.line.request.e_type == e_type;
  };
  tsip_message.prototype.is_ack = function () { return this.is_req_type(tsip_request_type_e.ACK); }
  tsip_message.prototype.is_bye = function () { return this.is_req_type(tsip_request_type_e.BYE); }
  tsip_message.prototype.is_cancel = function () { return this.is_req_type(tsip_request_type_e.CANCEL); }
  tsip_message.prototype.is_invite = function () { return this.is_req_type(tsip_request_type_e.INVITE); }
  tsip_message.prototype.is_options = function () { return this.is_req_type(tsip_request_type_e.OPTIONS); }
  tsip_message.prototype.is_register = function () { return this.is_req_type(tsip_request_type_e.REGISTER); }
  tsip_message.prototype.is_subscribe = function () { return this.is_req_type(tsip_request_type_e.SUBSCRIBE); }
  tsip_message.prototype.is_notify = function () { return this.is_req_type(tsip_request_type_e.NOTIFY); }
  tsip_message.prototype.is_update = function () { return this.is_req_type(tsip_request_type_e.UPDATE); }
  tsip_message.prototype.is_message = function () { return this.is_req_type(tsip_request_type_e.MESSAGE); }
  tsip_message.prototype.is_publish = function () { return this.is_req_type(tsip_request_type_e.PUBLISH); }
  tsip_message.prototype.is_prack = function () { return this.is_req_type(tsip_request_type_e.PRACK); }
  tsip_message.prototype.is_refer = function () { return this.is_req_type(tsip_request_type_e.REFER); }
  tsip_message.prototype.is_info = function () { return this.is_req_type(tsip_request_type_e.INFO); }
  
  tsip_message.prototype.is_response_to = function (e_req_type) {
       return this.is_response() && this.o_hdr_CSeq && this.o_hdr_CSeq.e_req_type == e_req_type;
  };
  tsip_message.prototype.is_response_to_ack = function () { return this.is_response_to(tsip_request_type_e.ACK); }
  tsip_message.prototype.is_response_to_bye = function () { return this.is_response_to(tsip_request_type_e.BYE); }
  tsip_message.prototype.is_response_to_cancel = function () { return this.is_response_to(tsip_request_type_e.CANCEL); }
  tsip_message.prototype.is_response_to_invite = function () { return this.is_response_to(tsip_request_type_e.INVITE); }
  tsip_message.prototype.is_response_to_options = function () { return this.is_response_to(tsip_request_type_e.OPTIONS); }
  tsip_message.prototype.is_response_to_register = function () { return this.is_response_to(tsip_request_type_e.REGISTER); }
  tsip_message.prototype.is_response_to_subscribe = function () { return this.is_response_to(tsip_request_type_e.SUBSCRIBE); }
  tsip_message.prototype.is_response_to_notify = function () { return this.is_response_to(tsip_request_type_e.NOTIFY); }
  tsip_message.prototype.is_response_to_update = function () { return this.is_response_to(tsip_request_type_e.UPDATE); }
  tsip_message.prototype.is_response_to_message = function () { return this.is_response_to(tsip_request_type_e.MESSAGE); }
  tsip_message.prototype.is_response_to_publish = function () { return this.is_response_to(tsip_request_type_e.PUBLISH); }
  tsip_message.prototype.is_response_to_prack = function () { return this.is_response_to(tsip_request_type_e.PRACK); }
  tsip_message.prototype.is_response_to_refer = function () { return this.is_response_to(tsip_request_type_e.REFER); }
  tsip_message.prototype.is_response_to_info = function () { return this.is_response_to(tsip_request_type_e.INFO); }
  
  tsip_message.prototype.is_response_nxx = function (i_n) {
      return this.is_response() && ((i_n * 100) <= this.get_response_code() && this.get_response_code() <= ((i_n * 100) + 99));
  }
  tsip_message.prototype.is_response_xxx = function (i_xxx) {
      return this.is_response() && (this.get_response_code() == i_xxx);
  }
  tsip_message.prototype.is_1xx = function () { return this.is_response_nxx(1); }
  tsip_message.prototype.is_2xx = function () { return this.is_response_nxx(2); }
  tsip_message.prototype.is_3xx = function () { return this.is_response_nxx(3); }
  tsip_message.prototype.is_4xx = function () { return this.is_response_nxx(4); }
  tsip_message.prototype.is_5xx = function () { return this.is_response_nxx(5); }
  tsip_message.prototype.is_6xx = function () { return this.is_response_nxx(6); }
  tsip_message.prototype.is_23456 = function () {
      return this.is_response() && (200 <= this.get_response_code() && this.get_response_code() <= 699);
  }
  tsip_message.prototype.is_3456 = function () {
      return this.is_response() && (300 <= this.get_response_code() && this.get_response_code() <= 699);
  }
  
  tsip_message.prototype.GetRequestType = function(s_method) {
      if (s_method) {
          var s_method_i = s_method.toUpperCase();
          if ((s_method_i == tsip_request_type_e.ACK.s_name)) {
              return tsip_request_type_e.ACK;
          } else if ((s_method_i == tsip_request_type_e.BYE.s_name)) {
              return tsip_request_type_e.BYE;
          } else if ((s_method_i == tsip_request_type_e.CANCEL.s_name)) {
              return tsip_request_type_e.CANCEL;
          } else if ((s_method_i == tsip_request_type_e.INVITE.s_name)) {
              return tsip_request_type_e.INVITE;
          } else if ((s_method_i == tsip_request_type_e.OPTIONS.s_name)) {
              return tsip_request_type_e.OPTIONS;
          } else if ((s_method_i == tsip_request_type_e.REGISTER.s_name)) {
              return tsip_request_type_e.REGISTER;
          } else if ((s_method_i == tsip_request_type_e.SUBSCRIBE.s_name)) {
              return tsip_request_type_e.SUBSCRIBE;
          } else if ((s_method_i == tsip_request_type_e.NOTIFY.s_name)) {
              return tsip_request_type_e.NOTIFY;
          } else if ((s_method_i == tsip_request_type_e.REFER.s_name)) {
              return tsip_request_type_e.REFER;
          } else if ((s_method_i == tsip_request_type_e.INFO.s_name)) {
              return tsip_request_type_e.INFO;
          } else if ((s_method_i == tsip_request_type_e.UPDATE.s_name)) {
              return tsip_request_type_e.UPDATE;
          } else if ((s_method_i == tsip_request_type_e.MESSAGE.s_name)) {
              return tsip_request_type_e.MESSAGE;
          } else if ((s_method_i == tsip_request_type_e.PUBLISH.s_name)) {
              return tsip_request_type_e.PUBLISH;
          } else if ((s_method_i == tsip_request_type_e.PRACK.s_name)) {
              return tsip_request_type_e.PRACK;
          }
      }
      return tsip_request_type_e.NONE;
  }
  
  if(!window.__b_release_mode){
      tsip_api_add_js_scripts('head',
      'src/tinySIP/src/parsers/tsip_parser_message.js'
      );
  }