doubango/bindings/_common/SipMessage.cxx
c732d49e
 /*
 * Copyright (C) 2017, University of the Basque Country (UPV/EHU)
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * The original file was part of Open Source Doubango Framework
 * Copyright (C) 2010-2011 Mamadou Diop.
 * Copyright (C) 2012 Doubango Telecom <http://doubango.org>
 *
 * This file is part of Open Source Doubango Framework.
 *
 * DOUBANGO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DOUBANGO is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with DOUBANGO.
 *
 */
 #include "SipMessage.h"
 #define VALUE_CONTENT_TYPE_MULTIPART "multipart/mixed"
 #define VALUE_CONTENT_TYPE_MESSAGE_MBMS "application/vnd.3gpp.mcptt-mbms-usage-info+xml"
 #define VALUE_CONTENT_TYPE_SDP "application/sdp"
 
 
 SdpMessage::SdpMessage()
 :m_pSdpMessage(tsk_null)
 {
 }
 
 SdpMessage::SdpMessage(tsdp_message_t *_sdpmessage)
 {
 	m_pSdpMessage = (tsdp_message_t *)tsk_object_ref(_sdpmessage);
 }
 
 SdpMessage::~SdpMessage()
 {
 	TSK_OBJECT_SAFE_FREE(m_pSdpMessage);
 }
 
 char* SdpMessage::getSdpHeaderValue(const char* media, char name, unsigned index /*= 0*/)
 {
 	const tsdp_header_M_t* M;
 
 	if((M = (const tsdp_header_M_t*)tsdp_message_get_header(m_pSdpMessage, tsdp_htype_M))){
 		tsdp_header_type_t type = tsdp_htype_Dummy;
 		const tsdp_header_t* header;
 		switch(name){
 			case 'a': type = tsdp_htype_A; break;
 			case 'b': type = tsdp_htype_B; break;
 			case 'c': type = tsdp_htype_C; break;
 			case 'e': type = tsdp_htype_E; break;
 			case 'i': type = tsdp_htype_I; break;
 			case 'k': type = tsdp_htype_K; break;
 			case 'm': type = tsdp_htype_M; break;
 			case 'o': type = tsdp_htype_O; break;
 
 
 			case 'p': type = tsdp_htype_P; break;
 			case 'r': type = tsdp_htype_R; break;
 			case 's': type = tsdp_htype_S; break;
 			case 't': type = tsdp_htype_T; break;
 			case 'u': type = tsdp_htype_U; break;
 			case 'v': type = tsdp_htype_V; break;
 			case 'z': type = tsdp_htype_Z; break;
 		}
 
 		if((header = tsdp_message_get_headerAt(m_pSdpMessage, type, index))){
 			return tsdp_header_tostring(header);
 		}
 	}
 		
 	return tsk_null;
 }
 
 char* SdpMessage::getSdpHeaderAValue(const char* media, const char* attributeName)
 {
 	const tsdp_header_M_t* M;
 	tsk_size_t i;
 
 	for(i = 0; (M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(m_pSdpMessage, tsdp_htype_M, i)); i++){
 		if(tsk_striequals(M->media, media)){
 			const tsdp_header_A_t* A;
 			if((A = tsdp_header_M_findA(M, attributeName))){
 				return tsk_strdup(A->value);
 			}
 		}
 	}
 	
 	return tsk_null;
 }
 
 int SdpMessage::getSdpHeaderMPort(const char* media, unsigned index /*= 0*/)
 {
 	const tsdp_header_M_t* M;
 	tsk_size_t i;
 	tsk_size_t con;
 	for(i = 0,con=0; (M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(m_pSdpMessage, tsdp_htype_M, i)); i++){
 		if(tsk_striequals(M->media, media)){
 			if(con>=index){
 				return M->port;
 			}else{
 				con++;
 			}
 			
 		}
 	}
 	
 	return -1;
 }
 
 
 char* SdpMessage::getSdpHeaderCAddr(const char* media, unsigned index /*= 0*/)
 {
 	const tsdp_header_M_t* M;
 	tsk_size_t i;
 	tsk_size_t con;
 	for(i = 0,con=0; (M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(m_pSdpMessage, tsdp_htype_M, i)); i++){
 		if(tsk_striequals(M->media, media)){
 			if(con>=index){
 				return tsk_strdup(M->C->addr);
 			}else{
 				con++;
 			}
 			
 		}
 	}
 	
 	return tsk_null;
 }
 
 char* SdpMessage::getSdpHeaderCAddrType(const char* media, unsigned index /*= 0*/)
 {
 	const tsdp_header_M_t* M;
 	tsk_size_t i;
 	tsk_size_t con;
 	for(i = 0,con=0; (M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(m_pSdpMessage, tsdp_htype_M, i)); i++){
 		if(tsk_striequals(M->media, media)){
 			if(con>=index){
 				return tsk_strdup(M->C->addrtype);
 			}else{
 				con++;
 			}
 			
 		}
 	}
 	
 	return tsk_null;
 }
 
 int SdpMessage::getSdpHeaderMPort(const char* media)
 {
 	return getSdpHeaderMPort(media,0);
 }
 
 SipMessage::SipMessage()
 :m_pSipMessage(tsk_null), m_pSdpMessage(tsk_null)
 { 
 }
 
 SipMessage::SipMessage(tsip_message_t *_sipmessage)
 : m_pSdpMessage(tsk_null)
 {
 	m_pSipMessage = (tsip_message_t *)tsk_object_ref(_sipmessage);
 }
 
 SipMessage::~SipMessage()
 {
 	TSK_OBJECT_SAFE_FREE(m_pSipMessage);
 	if(m_pSdpMessage){
 		delete m_pSdpMessage;
 	}
 }
 
 bool SipMessage::isResponse()
 {
 	return TSIP_MESSAGE_IS_RESPONSE(m_pSipMessage);
 }
 
 tsip_request_type_t SipMessage::getRequestType()
 {
 	if(TSIP_MESSAGE_IS_REQUEST(m_pSipMessage)){
 		return (m_pSipMessage)->line.request.request_type;
 	}
 	return tsip_NONE;
 }
 
 short SipMessage::getResponseCode()
 {
 	return TSIP_RESPONSE_CODE(m_pSipMessage);
 }
 
 const char* SipMessage::getResponsePhrase()
 {
 	return TSIP_RESPONSE_PHRASE(m_pSipMessage);
 }
 
 const tsip_header_t* SipMessage::getSipHeader(const char* name, unsigned index /* =0 */)
 {
 	/* Do not worry about calling tsk_striequals() several times because the function
 	* is fully optimized.
 	*/
 	/* Code below comes from tsip_message_get_headerAt() */
 	tsk_size_t pos = 0;
 	const tsk_list_item_t *item;
 	const tsip_header_t* hdr = tsk_null;
 	if(!m_pSipMessage || !name){
 		return tsk_null;
 	}			
 
 	if(tsk_striequals(name, "v") || tsk_striequals(name, "via")){
 		if(index == 0){
 			hdr = (const tsip_header_t*)m_pSipMessage->firstVia;
 			goto bail;
 		}else pos++; }
 	if(tsk_striequals(name, "f") || tsk_striequals(name, "from")){
 		if(index == 0){
 			hdr = (const tsip_header_t*)m_pSipMessage->From;
 			goto bail;
 		}else pos++; }
 	if(tsk_striequals(name, "t") || tsk_striequals(name, "to")){
 		if(index == 0){
 			hdr = (const tsip_header_t*)m_pSipMessage->To;
 			goto bail;
 		}else pos++; }
 	if(tsk_striequals(name, "m") || tsk_striequals(name, "contact")){
 		if(index == 0){
 			hdr = (const tsip_header_t*)m_pSipMessage->Contact;
 			goto bail;
 		}else pos++; }
 	if(tsk_striequals(name, "i") || tsk_striequals(name, "call-id")){
 		if(index == 0){
 			hdr = (const tsip_header_t*)m_pSipMessage->Call_ID;
 			goto bail;
 		}else pos++; }
 	if(tsk_striequals(name, "cseq")){
 		if(index == 0){
 			hdr = (const tsip_header_t*)m_pSipMessage->CSeq;
 			goto bail;
 		}else pos++; }
 	if(tsk_striequals(name, "expires")){
 		if(index == 0){
 			hdr = (const tsip_header_t*)m_pSipMessage->Expires;
 			goto bail;
 		}else pos++; }
 	if(tsk_striequals(name, "c") || tsk_striequals(name, "content-type")){
 		if(index == 0){
 			hdr = (const tsip_header_t*)m_pSipMessage->Content_Type;
 			goto bail;
 		}else pos++; }
 	if(tsk_striequals(name, "l") || tsk_striequals(name, "content-length")){
 		if(index == 0){
 			hdr = (const tsip_header_t*)m_pSipMessage->Content_Length;
 			goto bail;
 		}else pos++; }
 
 	tsk_list_foreach(item, m_pSipMessage->headers){
 		if(tsk_striequals(tsip_header_get_name_2(TSIP_HEADER(item->data)), name)){
 			if(pos++ >= index){
 				hdr = (const tsip_header_t*)item->data;
 				break;
 			}
 		}
 	}
 	
 
 bail:
 	return hdr;
 }
 
 // e.g. getHeaderParamValue("content-type");
 char* SipMessage::getSipHeaderValue(const char* name, unsigned index /* = 0*/)
 {
 	const tsip_header_t* header;
 	if((header = this->getSipHeader(name, index))){
 
 		switch(header->type){
 			case tsip_htype_From:
 				return tsip_uri_tostring(((const tsip_header_From_t*)header)->uri, tsk_false, tsk_false);
 			case tsip_htype_To:
 				return tsip_uri_tostring(((const tsip_header_To_t*)header)->uri, tsk_false, tsk_false);
 				break;
 			case tsip_htype_P_Asserted_Identity:
 				return tsip_uri_tostring(((const tsip_header_P_Asserted_Identity_t*)header)->uri, tsk_false, tsk_false);
 				break;
 
 			default:
 				return tsip_header_value_tostring(header);
 		}
 	}
 	// SWIG: %newobject getHeaderValueAt;
 	return tsk_null;
 }
 
 // e.g. getHeaderParamValue("content-type", "charset");
 char* SipMessage::getSipHeaderParamValue(const char* name, const char* param, unsigned index /*=0*/)
 {
 	const tsip_header_t* header;
 
 	if((header = this->getSipHeader(name, index))){
 		return tsip_header_get_param_value(header, param);
 	}
 
 	// SWIG: %newobject getSipHeaderParamValue;
 	return tsk_null;
 }
 
 /** Returns the content length.
 */
 unsigned SipMessage::getSipContentLength()
 {
 	return TSIP_MESSAGE_CONTENT_DATA_LENGTH(m_pSipMessage);
 }
 
 /*
 unsigned SipMessage::getSipContentMbms()
 {
 	return TSIP_MESSAGE_CONTENT_DATA_LENGTH(m_pSipMessage);
 }
 unsigned SipMessage::getSipContentSdp()
 {
 	return TSIP_MESSAGE_CONTENT_DATA_LENGTH(m_pSipMessage);
 }
 */
 /** Gets the message content
 * @param output A pointer to the output buffer where to copy the data. MUST
 * be allocated by the caller.
 * @param maxsize The maximum number of octets to copy. Should be less than the size of the
 * @a output buffer. You can use @a getSipContentLength() to get the right value to use.
 * @retval The number of octet copied in the @a output buffer.
 */
 unsigned SipMessage::getSipContent(void* output, unsigned maxsize)
 {
 	unsigned retsize = 0;
 	if(output && maxsize && TSIP_MESSAGE_HAS_CONTENT(m_pSipMessage)){
 		retsize = (m_pSipMessage->Content->size > maxsize) ? maxsize : m_pSipMessage->Content->size;
 		memcpy(output, m_pSipMessage->Content->data, retsize);
 	}
 	return retsize;
 }
 
 const void* SipMessage::getSipContentPtr()
 {
175b478c
     if(m_pSipMessage && m_pSipMessage->Content){
         return m_pSipMessage->Content->data;
     }
     return tsk_null;
c732d49e
 }
 
175b478c
 //MCPTT
c732d49e
 unsigned SipMessage::getSipContentSdp(void* output, unsigned maxsize)
 {
 	return getSipContentContetType(output, maxsize,VALUE_CONTENT_TYPE_SDP);
 }
175b478c
 //MCPTT MBMS
c732d49e
 unsigned SipMessage::getSipContentMbms(void* output, unsigned maxsize)
 {
 	return getSipContentContetType(output, maxsize,VALUE_CONTENT_TYPE_MESSAGE_MBMS);
 }
175b478c
 
 
 //MCPTT
c732d49e
 unsigned SipMessage::getSipContentContetType(void* output, unsigned maxsize,char* content_type)
 {
 	char* boundary = tsk_null;
 	tmedia_multipart_body_t* mp_body = tsk_null;
 	tmedia_content_multipart_t* mp_content = tsk_null;
 	tsip_header_t* content_type_data=tsk_null;
 	unsigned retsize = 0;
 	if(output && maxsize && TSIP_MESSAGE_HAS_CONTENT(m_pSipMessage)){
 		content_type_data=(tsip_header_t*)m_pSipMessage->Content_Type;
 		boundary = tsip_header_get_param_value(content_type_data, "boundary");
 		if(boundary == tsk_null) {			
 							TSK_DEBUG_ERROR("[%s] content-type is not supportted", TSIP_MESSAGE_CONTENT_TYPE(m_pSipMessage));
 							return -3;
 		}else{
 			mp_body = tmedia_content_multipart_body_parse(TSIP_MESSAGE_CONTENT_DATA(m_pSipMessage), TSIP_MESSAGE_CONTENT_DATA_LENGTH(m_pSipMessage), VALUE_CONTENT_TYPE_MULTIPART, boundary);
 			if(mp_body != tsk_null)
 			{
 				mp_content = tmedia_content_multipart_body_get_content(mp_body,content_type);
 				if(mp_content != tsk_null)
 				{
 					retsize = (mp_content->data_size > maxsize) ? maxsize : mp_content->data_size;
 					memcpy(output, mp_content->data, retsize);
 				}
 		
 			}
 		}
 			
 	}
 	return retsize;
 }
 
 const SdpMessage* SipMessage::getSdpMessage()
 {
 	char* sdpString=tsk_null;
 	if(!m_pSdpMessage && TSIP_MESSAGE_HAS_CONTENT(m_pSipMessage)){
 		tsdp_message_t* sdp = tsdp_message_parse(m_pSipMessage->Content->data, m_pSipMessage->Content->size);
 		if(sdp){
 			m_pSdpMessage = new SdpMessage(sdp);
 			TSK_OBJECT_SAFE_FREE(sdp);
 		}else{
 			#if HAVE_CRT //Debug memory
 		sdpString = (char*)malloc(getSipContentLength());
 			#else
 		sdpString = (char*)tsk_malloc(getSipContentLength());
 			#endif //HAVE_CRT
 			
 			int size=getSipContentSdp(sdpString,getSipContentLength());
 			tsdp_message_t* sdp = tsdp_message_parse(sdpString,size);
 			if(sdp){
 				m_pSdpMessage = new SdpMessage(sdp);
 				TSK_OBJECT_SAFE_FREE(sdp);
 			}
 		}
 	}
 	
 	return m_pSdpMessage;
 }