doubango/tinySIP/src/api/tsip_api_message.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
74ca6d11
 * Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 * 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.
 *
 */
 
 
 /**@file tsip_api_message.c
  * @brief Public short messaging (MESSAGE) functions.
  *
  * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
  *
 
  */
175b478c
 #include <tinysip/tsip_ssession.h>
c732d49e
 #include "tinysip/api/tsip_api_message.h"
 
 #include "tinysip/dialogs/tsip_dialog_layer.h"
 #include "tinysip/dialogs/tsip_dialog_message.h"
 #include "tinymedia/content/tmedia_content_multipart.h"
 #include "tinysip/headers/tsip_header_Dummy.h"
 #include "tinysip/tsip_message.h"
 #include "tsip.h"
 #include "tsk_memory.h"
 
 #include "tsk_runnable.h"
 #include "tsk_debug.h"
 
 #define TSIP_MESSAGE_EVENT_CREATE( type)		(tsip_message_event_t*)tsk_object_new(tsip_message_event_def_t, type)
 #define VALUE_CONTENT_TYPE_MESSAGE_LOCATION "application/vnd.3gpp.mcptt-location-info+xml"
175b478c
 
c732d49e
 #define VALUE_CONTENT_TYPE_MESSAGE_AFFILIATION "application/vnd.3gpp.mcptt-affiliation-command+xml"
 #define VALUE_CONTENT_TYPE_MESSAGE_MBMS "application/vnd.3gpp.mcptt-mbms-usage-info+xml"
 #define VALUE_P_ASSERTED_SERVICE_MESSAGE_AFFILIATION "urn:urn-7:3gpp-service.ims.icsi.mcptt"
 #define VALUE_P_ASSERTED_SERVICE_MESSAGE_MBMS "urn:urn-7:3gpp-service.ims.icsi.mcptt"
 #define VALUE_CONTENT_TYPE_MULTIPART "multipart/mixed"
 
 extern tsip_action_t* _tsip_action_create(tsip_action_type_t type, va_list* app);
 
175b478c
 
 #if HAVE_LIBXML2
 static int register_xml_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList)
 {
     xmlChar* nsListDup;
     xmlChar* prefix;
     xmlChar* href;
     xmlChar* next;
 
     nsListDup = xmlStrdup(nsList);
 
     if(nsListDup == NULL)
     {
         return(-1);
     }
     next = nsListDup;
 
     while(next != NULL)
     {
         /* skip spaces */
         while((*next) == ' ') next++;
         if((*next) == '\0') break;
 
         /* find prefix */
         prefix = next;
         next = (xmlChar*)xmlStrchr(next, '=');
 
         if(next == NULL)
         {
             xmlFree(nsListDup);
             return(-1);
         }
 
         *(next++) = '\0';
 
         /* find href */
         href = next;
         next = (xmlChar*)xmlStrchr(next, ' ');
         if(next != NULL)
         {
             *(next++) = '\0';
         }
 
         if(href[0] == '\"' || href[0] == '\'')
         {
             href = href + 1;
             if(href[strlen(href) - 1]  == '\"' || href[strlen(href) - 1] == '\'')
                 href[strlen(href) - 1] = '\0';
         }
 
         /* do register namespace */
         if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0)
         {
             xmlFree(nsListDup);
             return(-1);
         }
     }
     xmlFree(nsListDup);
     return(0);
 }
 #endif
 
c732d49e
 int tsip_message_event_signal(tsip_message_event_type_t type, tsip_ssession_handle_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage)
 {
 	
 	
 	tsip_message_event_t* sipevent = TSIP_MESSAGE_EVENT_CREATE(type);
 	
 	tmedia_content_multipart_t* mp_content = tsk_null;
 	tmedia_content_multipart_t* mp_content_sdp = tsk_null;
 	tmedia_multipart_body_t* mp_body = tsk_null;
 	char* boundary = tsk_null;
 	const tsip_header_t* header =tsk_null;
 	char* hdr_value=tsk_null;
 	uint32_t local_ssrc = 0;
 	char* psi_mbms_value=tsk_null;
 	//tmedia_session_t* audio_session;
 	//tsdp_message_t* sdp_ro = tsk_null;
 	int con=0;
 	char* sdp=tsk_null;
 	tsip_message_t* sipmessage2=tsk_null;
175b478c
 
c732d49e
 	//if the messager is send
 	if((((tsip_ssession_t*)ss)->media.type & tmedia_mcptt_location) == tmedia_mcptt_location){
 		tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_location);
 	
 	}else 
 	
 		if(tsk_strcmp(TSIP_MESSAGE_CONTENT_TYPE(sipmessage),VALUE_CONTENT_TYPE_MESSAGE_LOCATION)==0){//it receive message
 		tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_location);
 	
 	}else 
 		if(
 		tsk_strcmp(TSIP_MESSAGE_CONTENT_TYPE(sipmessage),VALUE_CONTENT_TYPE_MESSAGE_AFFILIATION)==0){//it receive message
 		for(con=0; (header = tsip_message_get_headerAt(sipmessage, tsip_htype_Dummy, con)); con++)
 		{		
 			 const tsip_header_Dummy_t* dummy_hdr = (const tsip_header_Dummy_t*)header;
 
 			if(tsk_strcmp(dummy_hdr->name, "P-Asserted-Service") == 0)
 			{
 				#if HAVE_CRT //Debug memory
 					hdr_value = (char *)malloc(tsk_strlen(dummy_hdr->value) * sizeof(char));
 	
 				#else
 					hdr_value = (char *)tsk_malloc(tsk_strlen(dummy_hdr->value) * sizeof(char));
 	
 				#endif //HAVE_CRT
 				hdr_value=strdup(dummy_hdr->value);
 				break;
 			}
 	/*				else if(tsk_strcmp(dummy_hdr->name, "User-Agent") == 0)
 			{
 				len = tsk_strlen(dummy_hdr->value) + 19;
 				hdr_value = (char *)malloc(len * sizeof(char));
 				tsk_sprintf(&hdr_value, "PoC-client/OMA_PCPS_1.0 %s", dummy_hdr->value);
 				tsk_object_delete(dummy_hdr->value);
 	
 			}*/
 		}
 		if((hdr_value)!=tsk_null &&
 		tsk_strcmp(hdr_value,VALUE_P_ASSERTED_SERVICE_MESSAGE_AFFILIATION)==0 ){
 			tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_affiliation);
 		}
 		TSK_FREE(hdr_value);
 		
 	}else if(tsk_striequals(VALUE_CONTENT_TYPE_MULTIPART, TSIP_MESSAGE_CONTENT_TYPE(sipmessage))){
 		//multipart/mixed
 		boundary = tsip_header_get_param_value((tsip_header_t*)sipmessage->Content_Type, "boundary");
 			if(boundary != tsk_null) 
 			{			
 				mp_body = tmedia_content_multipart_body_parse(TSIP_MESSAGE_CONTENT_DATA(sipmessage), TSIP_MESSAGE_CONTENT_DATA_LENGTH(sipmessage), VALUE_CONTENT_TYPE_MULTIPART, boundary);
 				if(mp_body != tsk_null)
 				{
 					mp_content = tmedia_content_multipart_body_get_content(mp_body,VALUE_CONTENT_TYPE_MESSAGE_LOCATION);
 					if(mp_content != tsk_null)//Location
 					{	
 						//change de content for format location
175b478c
                         TSK_FREE(sipmessage->Content->data);
 						if ((sipmessage->Content->data = (char*)tsk_calloc((mp_content->data_size) + 1, sizeof(uint8_t)))) {
 						    memcpy(sipmessage->Content->data, mp_content->data, mp_content->data_size);
                             ((char *)sipmessage->Content->data)[mp_content->data_size]='\0';
 						}
c732d49e
 						sipmessage->Content->size=mp_content->data_size;
 						tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_location);
175b478c
 					}else
 					if(1){
 
c732d49e
 						mp_content = tmedia_content_multipart_body_get_content(mp_body,VALUE_CONTENT_TYPE_MESSAGE_AFFILIATION);
 						
 						if(mp_content != tsk_null )//Affiliation
 						{	
 							for(con=0; (header = tsip_message_get_headerAt(sipmessage, tsip_htype_Dummy, con)); con++)
 							{		
 								const tsip_header_Dummy_t* dummy_hdr = (const tsip_header_Dummy_t*)header;
 								if(tsk_strcmp(dummy_hdr->name, "P-Asserted-Service") == 0)
 								{
 									#if HAVE_CRT //Debug memory
 									hdr_value = (char *)malloc(tsk_strlen(dummy_hdr->value) * sizeof(char));
 		
 									#else
 									hdr_value = (char *)tsk_malloc(tsk_strlen(dummy_hdr->value) * sizeof(char));
 		
 									#endif //HAVE_CRT
 									hdr_value=strdup(dummy_hdr->value);
 									break;
 								}
 				
 							}
 							if((hdr_value)!=tsk_null &&
 							tsk_strcmp(hdr_value,VALUE_P_ASSERTED_SERVICE_MESSAGE_AFFILIATION)==0 ){
 								//change de content for format affiliation
 								//tsk_realloc(sipmessage->Content->data,mp_content->data_size);
 								TSK_FREE(sipmessage->Content->data)
 								sipmessage->Content->data=tsk_strndup(mp_content->data,mp_content->data_size);
 								sipmessage->Content->size=mp_content->data_size;
 								tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_affiliation);
 							}
 							
 						}
 						else{
 							
 							tmedia_multipart_body_t* body = tsk_null;
 							char* content_type_hdr  = tsk_null;
 							char* body_string = tsk_null;
 							
 							//mp_content is xml of MBMS
 							mp_content = tmedia_content_multipart_body_get_content(mp_body,VALUE_CONTENT_TYPE_MESSAGE_MBMS);
 							//mp_content_sdp is the data in char* of SDP
 							mp_content_sdp = tmedia_content_multipart_body_get_content(mp_body, "application/sdp");
 			
 							if(mp_content != tsk_null && mp_content_sdp!=tsk_null)//MBMS service
 							{	
 								for(con=0; (header = tsip_message_get_headerAt(sipmessage, tsip_htype_Dummy, con)); con++)
 								{		
 									const tsip_header_Dummy_t* dummy_hdr = (const tsip_header_Dummy_t*)header;
 									if(tsk_strcmp(dummy_hdr->name, "P-Asserted-Service") == 0)
 									{
 										#if HAVE_CRT //Debug memory
 												hdr_value = (char *)malloc(tsk_strlen(dummy_hdr->value) * sizeof(char));
 
 										#else
 												hdr_value = (char *)tsk_malloc(tsk_strlen(dummy_hdr->value) * sizeof(char));
 
 										#endif //HAVE_CRT
 										hdr_value=strdup(dummy_hdr->value);
 										break;
 									}
 				
 								}
 								
 								//SDP of MBMS message
 								if(mp_content_sdp == tsk_null){
 									TSK_DEBUG_ERROR("content-type is not supportted");
 									return -3;
 								}
 
 
 									
 
 									if((hdr_value)!=tsk_null &&
 									tsk_strcmp(hdr_value,VALUE_P_ASSERTED_SERVICE_MESSAGE_MBMS)==0 ){
 										body = tmedia_content_multipart_body_create("multipart/mixed", tsk_null);
 										if(body)
 										{
 										  tmedia_content_multipart_body_add_content(body, mp_content_sdp);
 										  tmedia_content_multipart_body_add_content(body, mp_content);
 										  body_string =tmedia_content_multipart_body_tostring(body);
 										  content_type_hdr = tmedia_content_multipart_body_get_header(body);
 										  sipmessage2=tsip_message_create();
 										  tsip_message_add_content(sipmessage2, content_type_hdr, body_string, tsk_strlen(body_string));
 										}
 										
 										/*
 										//change de content for format MBMS
 										tsk_realloc(sipmessage->Content->data,mp_content->data_size);
 										strcpy(sipmessage->Content->data, mp_content->data);
 										sipmessage->Content->size=mp_content->data_size;
 										*/
 										tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message_mbms);
 									}
 							}else{
 								TSK_DEBUG_ERROR("The new message isn't valid.");
 								tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message);
 							}
 							
 						}
 						}
 				}
 			}else{
 				tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message);
 			}
 	}else
 		tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_message);
 
 	if(hdr_value)
 		TSK_FREE(hdr_value);
 
 	TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent);
 
 	return 0;
 }
 
 int tsip_api_message_send_message(const tsip_ssession_handle_t *ss, ...)
 {
 	const tsip_ssession_t* _ss;
 	va_list ap;
 	tsip_action_t* action;
 	tsip_dialog_t* dialog;
 	int ret = -1;
 
 	if(!(_ss = ss) || !_ss->stack){
 		TSK_DEBUG_ERROR("Invalid parameter.");
 		return ret;
 	}
 	
 	/* Checks if the stack has been started */
 	if(!TSK_RUNNABLE(_ss->stack)->started){
 		TSK_DEBUG_ERROR("Stack not started.");
 		return -2;
 	}
 
 	/* action */
 	va_start(ap, ss);
 	if((action = _tsip_action_create(tsip_atype_message_send, &ap))){
 		if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){
 			dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_MESSAGE, ss);
 		}
 		ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action);
 		
 		tsk_object_unref(dialog);
 		TSK_OBJECT_SAFE_FREE(action);
 	}
 	va_end(ap);
 
 	return ret;
 }
175b478c
 //Location
c732d49e
 int tsip_api_message_send_message_location(const tsip_ssession_handle_t *ss, ...)
 {
 	const tsip_ssession_t* _ss;
 	va_list ap;
 	tsip_action_t* action;
 	tsip_dialog_t* dialog;
 	int ret = -1;
 
 
 
 	if(!(_ss = ss) || !_ss->stack){
 		TSK_DEBUG_ERROR("Invalid parameter.");
 		return ret;
 	}
 	
 	/* Checks if the stack has been started */
 	if(!TSK_RUNNABLE(_ss->stack)->started){
 		TSK_DEBUG_ERROR("Stack not started.");
 		return -2;
 	}
 
 	//This session is type MCPTT location
 	((tsip_ssession_t*)ss)->media.type=tmedia_mcptt_location;
 
 	/* action */
 	va_start(ap, ss);
 	if((action = _tsip_action_create(tsip_atype_message_send, &ap))){
 		if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){
 			dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_MESSAGE, ss);
 		}
 		ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action);
 		
 		tsk_object_unref(dialog);
 		TSK_OBJECT_SAFE_FREE(action);
 	}
 	va_end(ap);
 
 	return ret;
 }
175b478c
 //MBMS
c732d49e
 int tsip_api_message_send_message_mbms(const tsip_ssession_handle_t *ss, ...)
 {
 	const tsip_ssession_t* _ss;
 	va_list ap;
 	tsip_action_t* action;
 	tsip_dialog_t* dialog;
 	int ret = -1;
 
 
 
 	if(!(_ss = ss) || !_ss->stack){
 		TSK_DEBUG_ERROR("Invalid parameter.");
 		return ret;
 	}
 	
 	/* Checks if the stack has been started */
 	if(!TSK_RUNNABLE(_ss->stack)->started){
 		TSK_DEBUG_ERROR("Stack not started.");
 		return -2;
 	}
 	//This session is type MCPTT MBMS
 	((tsip_ssession_t*)ss)->media.type=tmedia_mcptt_mbms;
 	
 	/* action */
 	va_start(ap, ss);
 	if((action = _tsip_action_create(tsip_atype_message_send, &ap))){
 		if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){
 			dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_MESSAGE, ss);
 		}
 		ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action);
 		
 		tsk_object_unref(dialog);
 		TSK_OBJECT_SAFE_FREE(action);
 	}
 	va_end(ap);
 
 	return ret;
 }
 
 
 
 
 
 
 
 
 //========================================================
 //	SIP MESSAGE event object definition
 //
 static tsk_object_t* tsip_message_event_ctor(tsk_object_t * self, va_list * app)
 {
 	tsip_message_event_t *sipevent = self;
 	if(sipevent){
 		sipevent->type = va_arg(*app, tsip_message_event_type_t);
 	}
 	return self;
 }
 
 static tsk_object_t* tsip_message_event_dtor(tsk_object_t * self)
 { 
 	tsip_message_event_t *sipevent = self;
 	if(sipevent){
 		tsip_event_deinit(TSIP_EVENT(sipevent));
 	}
 	return self;
 }
 
 static int tsip_message_event_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
 {
 	return -1;
 }
 
 static const tsk_object_def_t tsip_message_event_def_s = 
 {
 	sizeof(tsip_message_event_t),
 	tsip_message_event_ctor, 
 	tsip_message_event_dtor,
 	tsip_message_event_cmp, 
 };
 const tsk_object_def_t *tsip_message_event_def_t = &tsip_message_event_def_s;